Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3145 lines
81 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
nls.c
Abstract:
This module implements NLS support functions for NT.
Author:
Mark Lucovsky (markl) 16-Apr-1991
Environment:
Kernel or user-mode
Revision History:
16-Feb-1993 JulieB Added Upcase Rtl Routines.
08-Mar-1993 JulieB Moved Upcase Macro to ntrtlp.h.
02-Apr-1993 JulieB Fixed RtlAnsiCharToUnicodeChar to use transl. tbls.
02-Apr-1993 JulieB Fixed BUFFER_TOO_SMALL check.
28-May-1993 JulieB Fixed code to properly handle DBCS.
--*/
#include "ntrtlp.h"
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
#pragma alloc_text(PAGE,RtlAnsiStringToUnicodeString)
#pragma alloc_text(PAGE,RtlAnsiCharToUnicodeChar)
#pragma alloc_text(PAGE,RtlUnicodeStringToAnsiString)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToAnsiString)
#pragma alloc_text(PAGE,RtlOemStringToUnicodeString)
#pragma alloc_text(PAGE,RtlUnicodeStringToOemString)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToOemString)
#pragma alloc_text(PAGE,RtlOemStringToCountedUnicodeString)
#pragma alloc_text(PAGE,RtlUnicodeStringToCountedOemString)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeStringToCountedOemString)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeString)
#pragma alloc_text(PAGE,RtlDowncaseUnicodeString)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeChar)
#pragma alloc_text(PAGE,RtlDowncaseUnicodeChar)
#pragma alloc_text(PAGE,RtlFreeUnicodeString)
#pragma alloc_text(PAGE,RtlFreeAnsiString)
#pragma alloc_text(PAGE,RtlFreeOemString)
#pragma alloc_text(PAGE,RtlxUnicodeStringToAnsiSize)
#pragma alloc_text(PAGE,RtlxUnicodeStringToOemSize)
#pragma alloc_text(PAGE,RtlxAnsiStringToUnicodeSize)
#pragma alloc_text(PAGE,RtlxOemStringToUnicodeSize)
#pragma alloc_text(PAGE,RtlCompareUnicodeString)
#pragma alloc_text(PAGE,RtlEqualUnicodeString)
#pragma alloc_text(PAGE,RtlPrefixUnicodeString)
#pragma alloc_text(PAGE,RtlCreateUnicodeString)
#pragma alloc_text(PAGE,RtlEqualDomainName)
#pragma alloc_text(PAGE,RtlEqualComputerName)
#pragma alloc_text(PAGE,RtlIsTextUnicode)
#pragma alloc_text(PAGE,RtlDnsHostNameToComputerName)
#pragma alloc_text(PAGE,RtlHashUnicodeString)
#pragma alloc_text(PAGE,RtlDuplicateUnicodeString)
#pragma alloc_text(PAGE,RtlFindCharInUnicodeString)
#endif
//
// Global data used for translations.
//
extern const PUSHORT NlsAnsiToUnicodeData; // Ansi CP to Unicode translation table
extern const PUSHORT NlsLeadByteInfo; // Lead byte info for ACP
//
// Pulled from lmcons.h:
//
#ifndef NETBIOS_NAME_LEN
#define NETBIOS_NAME_LEN 16 // NetBIOS net name (bytes)
#endif // NETBIOS_NAME_LEN
NTSTATUS
RtlAnsiStringToUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCANSI_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions converts the specified ansi source string into a
Unicode string. The translation is done with respect to the
current system locale information.
Arguments:
DestinationString - Returns a unicode string that is equivalent to
the ansi source string. The maximum length field is only
set if AllocateDestinationString is TRUE.
SourceString - Supplies the ansi source string that is to be
converted to unicode.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeUnicodeString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG UnicodeLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
UnicodeLength = RtlAnsiStringToUnicodeSize(SourceString);
if ( UnicodeLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)UnicodeLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlMultiByteToUnicodeN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
return STATUS_SUCCESS;
}
WCHAR
RtlAnsiCharToUnicodeChar(
IN OUT PUCHAR *SourceCharacter
)
/*++
Routine Description:
This function translates the specified ansi character to unicode and
returns the unicode value. The purpose for this routine is to allow
for character by character ansi to unicode translation. The
translation is done with respect to the current system locale
information.
Arguments:
SourceCharacter - Supplies a pointer to an ansi character pointer.
Through two levels of indirection, this supplies an ansi
character that is to be translated to unicode. After
translation, the ansi character pointer is modified to point to
the next character to be converted. This is done to allow for
dbcs ansi characters.
Return Value:
Returns the unicode equivalent of the specified ansi character.
--*/
{
WCHAR UnicodeCharacter;
ULONG cbCharSize;
NTSTATUS st;
RTL_PAGED_CODE();
//
// Translate the ansi character to unicode - this handles DBCS.
//
UnicodeCharacter = 0x0020;
cbCharSize = NlsLeadByteInfo[ **SourceCharacter ] ? 2 : 1;
st = RtlMultiByteToUnicodeN ( &UnicodeCharacter,
sizeof ( WCHAR ),
NULL,
*SourceCharacter,
cbCharSize );
//
// Check for error - The only time this will happen is if there is
// a leadbyte without a trail byte.
//
if ( ! NT_SUCCESS( st ) )
{
// Use space as default.
UnicodeCharacter = 0x0020;
}
//
// Advance the source pointer and return the Unicode character.
//
(*SourceCharacter) += cbCharSize;
return UnicodeCharacter;
}
NTSTATUS
RtlUnicodeStringToAnsiString(
OUT PANSI_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions converts the specified unicode source string into an
ansi string. The translation is done with respect to the
current system locale information.
Arguments:
DestinationString - Returns an ansi string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned. The maximum length field is only set if
AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to be
converted to ansi.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeAnsiString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG AnsiLength;
ULONG Index;
NTSTATUS st;
NTSTATUS ReturnStatus = STATUS_SUCCESS;
RTL_PAGED_CODE();
AnsiLength = RtlUnicodeStringToAnsiSize(SourceString);
if ( AnsiLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(AnsiLength - 1);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)AnsiLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(AnsiLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
/*
* Return STATUS_BUFFER_OVERFLOW, but translate as much as
* will fit into the buffer first. This is the expected
* behavior for routines such as GetProfileStringA.
* Set the length of the buffer to one less than the maximum
* (so that the trail byte of a double byte char is not
* overwritten by doing DestinationString->Buffer[Index] = '\0').
* RtlUnicodeToMultiByteN is careful not to truncate a
* multibyte character.
*/
if (!DestinationString->MaximumLength) {
return STATUS_BUFFER_OVERFLOW;
}
ReturnStatus = STATUS_BUFFER_OVERFLOW;
DestinationString->Length = DestinationString->MaximumLength - 1;
}
}
st = RtlUnicodeToMultiByteN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
DestinationString->Buffer[Index] = '\0';
return ReturnStatus;
}
NTSTATUS
RtlUpcaseUnicodeStringToAnsiString(
OUT PANSI_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions upper cases the specified unicode source string and then
converts it into an ansi string. The translation is done with respect
to the current system locale information.
Arguments:
DestinationString - Returns an ansi string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned. The maximum length field is only set
if AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to be
converted to upper case ansi.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeAnsiString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG AnsiLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
AnsiLength = RtlUnicodeStringToAnsiSize(SourceString);
if ( AnsiLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(AnsiLength - 1);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)AnsiLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(AnsiLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlUpcaseUnicodeToMultiByteN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
DestinationString->Buffer[Index] = '\0';
return STATUS_SUCCESS;
}
NTSTATUS
RtlOemStringToUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCOEM_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions converts the specified oem source string into a
Unicode string. The translation is done with respect to the
installed OEM code page (OCP).
Arguments:
DestinationString - Returns a unicode string that is equivalent to
the oem source string. The maximum length field is only
set if AllocateDestinationString is TRUE.
SourceString - Supplies the oem source string that is to be
converted to unicode.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeUnicodeString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG UnicodeLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
UnicodeLength = RtlOemStringToUnicodeSize(SourceString);
if ( UnicodeLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)UnicodeLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlOemToUnicodeN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
return STATUS_SUCCESS;
}
NTSTATUS
RtlUnicodeStringToOemString(
OUT POEM_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
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).
Arguments:
DestinationString - Returns an oem string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned. The maximum length field is only set if
AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to be
converted to oem.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeAnsiString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG OemLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
OemLength = RtlUnicodeStringToOemSize(SourceString);
if ( OemLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(OemLength - 1);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)OemLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlUnicodeToOemN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
DestinationString->Buffer[Index] = '\0';
return STATUS_SUCCESS;
}
NTSTATUS
RtlUpcaseUnicodeStringToOemString(
OUT POEM_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This function upper cases the specified unicode source string and then
converts it into an oem string. The translation is done with respect
to the OEM code page (OCP).
Arguments:
DestinationString - Returns an oem string that is equivalent to the
unicode source string. The maximum length field is only set if
AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to be
converted to oem.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeAnsiString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG OemLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
OemLength = RtlUnicodeStringToOemSize(SourceString);
if ( OemLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(OemLength - 1);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)OemLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length >= DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlUpcaseUnicodeToOemN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
//
// Now do a check here to see if there was really a mapping for all
// characters converted.
//
if (NT_SUCCESS(st) &&
!RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
st = STATUS_UNMAPPABLE_CHARACTER;
}
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
DestinationString->Buffer[Index] = '\0';
return STATUS_SUCCESS;
}
NTSTATUS
RtlOemStringToCountedUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCOEM_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions converts the specified oem source string into a
Unicode string. The translation is done with respect to the
installed OEM code page (OCP).
The destination string is NOT unnaturally null terminated. It is a
counted string as counted strings are meant to be.
Arguments:
DestinationString - Returns a unicode string that is equivalent to
the oem source string. The maximum length field is only
set if AllocateDestinationString is TRUE.
SourceString - Supplies the oem source string that is to be
converted to unicode.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeUnicodeString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG UnicodeLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
UnicodeLength = RtlOemStringToCountedUnicodeSize(SourceString);
if ( UnicodeLength == 0 ) {
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
return STATUS_SUCCESS;
}
if ( UnicodeLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(UnicodeLength);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)UnicodeLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(UnicodeLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length > DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlOemToUnicodeN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUnicodeStringToCountedOemString(
OUT POEM_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
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).
The destination string is NOT unnaturally null terminated. It is a
counted string as counted strings are meant to be.
Arguments:
DestinationString - Returns an oem string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned. The maximum length field is only set if
AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to be
converted to oem.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeAnsiString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG OemLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
OemLength = RtlUnicodeStringToCountedOemSize(SourceString);
if ( OemLength == 0 ) {
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
return STATUS_SUCCESS;
}
if ( OemLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(OemLength);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)OemLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length > DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlUnicodeToOemN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
//
// Now do a check here to see if there was really a mapping for all
// characters converted.
//
if (NT_SUCCESS(st) &&
!RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
st = STATUS_UNMAPPABLE_CHARACTER;
}
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUpcaseUnicodeStringToCountedOemString(
OUT POEM_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions upper cases the specified unicode source string and
then converts it into an oem string. The translation is done with
respect to the OEM code page (OCP).
The destination string is NOT unnaturally null terminated. It is a
counted string as counted strings are meant to be.
Arguments:
DestinationString - Returns an oem string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned. The maximum length field is only set
if AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to be
converted to oem.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeAnsiString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG OemLength;
ULONG Index;
NTSTATUS st;
RTL_PAGED_CODE();
OemLength = RtlUnicodeStringToCountedOemSize(SourceString);
if ( OemLength == 0 ) {
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
return STATUS_SUCCESS;
}
if ( OemLength > MAXUSHORT ) {
return STATUS_INVALID_PARAMETER_2;
}
DestinationString->Length = (USHORT)(OemLength);
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = (USHORT)OemLength;
DestinationString->Buffer = (RtlAllocateStringRoutine)(OemLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( DestinationString->Length > DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
st = RtlUpcaseUnicodeToOemN(
DestinationString->Buffer,
DestinationString->Length,
&Index,
SourceString->Buffer,
SourceString->Length
);
//
// Now do a check here to see if there was really a mapping for all
// characters converted.
//
if (NT_SUCCESS(st) &&
!RtlpDidUnicodeToOemWork( DestinationString, SourceString )) {
st = STATUS_UNMAPPABLE_CHARACTER;
}
if (!NT_SUCCESS(st)) {
if ( AllocateDestinationString ) {
(RtlFreeStringRoutine)(DestinationString->Buffer);
DestinationString->Buffer = NULL;
}
return st;
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUpcaseUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions converts the specified unicode source string into an
upcased unicode string. The translation is done with respect to the
current system locale information.
Arguments:
DestinationString - Returns a unicode string that is the upcased equivalent
to the unicode source string. The maximum length field is only set if
AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to being
upcased.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeUnicodeString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG Index;
ULONG StopIndex;
RTL_PAGED_CODE();
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = SourceString->Length;
DestinationString->Buffer = (RtlAllocateStringRoutine)((ULONG)DestinationString->MaximumLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( SourceString->Length > DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
for (Index = 0; Index < StopIndex; Index++) {
DestinationString->Buffer[Index] = (WCHAR)NLS_UPCASE(SourceString->Buffer[Index]);
}
DestinationString->Length = SourceString->Length;
return STATUS_SUCCESS;
}
NTSTATUS
RtlDowncaseUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
)
/*++
Routine Description:
This functions converts the specified unicode source string into a
downcased unicode string. The translation is done with respect to the
current system locale information.
Arguments:
DestinationString - Returns a unicode string that is the downcased
equivalent to the unicode source string. The maximum length field
is only set if AllocateDestinationString is TRUE.
SourceString - Supplies the unicode source string that is to being
downcased.
AllocateDestinationString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeUnicodeString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The operation failed. No storage was allocated and no
conversion was done. None.
--*/
{
ULONG Index;
ULONG StopIndex;
RTL_PAGED_CODE();
if ( AllocateDestinationString ) {
DestinationString->MaximumLength = SourceString->Length;
DestinationString->Buffer = (RtlAllocateStringRoutine)((ULONG)DestinationString->MaximumLength);
if ( !DestinationString->Buffer ) {
return STATUS_NO_MEMORY;
}
}
else {
if ( SourceString->Length > DestinationString->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
}
StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
for (Index = 0; Index < StopIndex; Index++) {
DestinationString->Buffer[Index] = (WCHAR)NLS_DOWNCASE(SourceString->Buffer[Index]);
}
DestinationString->Length = SourceString->Length;
return STATUS_SUCCESS;
}
WCHAR
RtlUpcaseUnicodeChar(
IN WCHAR SourceCharacter
)
/*++
Routine Description:
This function translates the specified unicode character to its
equivalent upcased unicode chararacter. The purpose for this routine
is to allow for character by character upcase translation. The
translation is done with respect to the current system locale
information.
Arguments:
SourceCharacter - Supplies the unicode character to be upcased.
Return Value:
Returns the upcased unicode equivalent of the specified input character.
--*/
{
RTL_PAGED_CODE();
//
// Note that this needs to reference the translation table !
//
return (WCHAR)NLS_UPCASE(SourceCharacter);
}
WCHAR
RtlDowncaseUnicodeChar(
IN WCHAR SourceCharacter
)
/*++
Routine Description:
This function translates the specified unicode character to its
equivalent downcased unicode chararacter. The purpose for this routine
is to allow for character by character downcase translation. The
translation is done with respect to the current system locale
information.
Arguments:
SourceCharacter - Supplies the unicode character to be downcased.
Return Value:
Returns the downcased unicode equivalent of the specified input character.
--*/
{
RTL_PAGED_CODE();
//
// Note that this needs to reference the translation table !
//
return (WCHAR)NLS_DOWNCASE(SourceCharacter);
}
VOID
RtlFreeUnicodeString(
IN OUT PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This API is used to free storage allocated by
RtlAnsiStringToUnicodeString. Note that only UnicodeString->Buffer
is free'd by this routine.
Arguments:
UnicodeString - Supplies the address of the unicode string whose
buffer was previously allocated by RtlAnsiStringToUnicodeString.
Return Value:
None.
--*/
{
RTL_PAGED_CODE();
if (UnicodeString->Buffer) {
(RtlFreeStringRoutine)(UnicodeString->Buffer);
memset( UnicodeString, 0, sizeof( *UnicodeString ) );
}
}
VOID
RtlFreeAnsiString(
IN OUT PANSI_STRING AnsiString
)
/*++
Routine Description:
This API is used to free storage allocated by
RtlUnicodeStringToAnsiString. Note that only AnsiString->Buffer
is free'd by this routine.
Arguments:
AnsiString - Supplies the address of the ansi string whose buffer
was previously allocated by RtlUnicodeStringToAnsiString.
Return Value:
None.
--*/
{
RTL_PAGED_CODE();
if (AnsiString->Buffer) {
(RtlFreeStringRoutine)(AnsiString->Buffer);
memset( AnsiString, 0, sizeof( *AnsiString ) );
}
}
VOID
RtlFreeOemString(
IN OUT POEM_STRING OemString
)
/*++
Routine Description:
This API is used to free storage allocated by
RtlUnicodeStringToOemString. Note that only OemString->Buffer
is free'd by this routine.
Arguments:
OemString - Supplies the address of the oem string whose buffer
was previously allocated by RtlUnicodeStringToOemString.
Return Value:
None.
--*/
{
RTL_PAGED_CODE();
if (OemString->Buffer) {(RtlFreeStringRoutine)(OemString->Buffer);}
}
ULONG
RtlxUnicodeStringToAnsiSize(
IN PCUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This function computes the number of bytes required to store
a NULL terminated ansi string that is equivalent to the specified
unicode string. If an ansi string can not be formed, the return value
is 0.
Arguments:
UnicodeString - Supplies a unicode string whose equivalent size as
an ansi string is to be calculated.
Return Value:
0 - The operation failed, the unicode string can not be translated
into ansi using the current system locale therefore no storage
is needed for the ansi string.
!0 - The operation was successful. The return value specifies the
number of bytes required to hold an NULL terminated ansi string
equivalent to the specified unicode string.
--*/
{
ULONG cbMultiByteString;
RTL_PAGED_CODE();
//
// Get the size of the string - this call handles DBCS.
//
RtlUnicodeToMultiByteSize( &cbMultiByteString,
UnicodeString->Buffer,
UnicodeString->Length );
//
// Return the size in bytes.
//
return (cbMultiByteString + 1);
}
ULONG
RtlxUnicodeStringToOemSize(
IN PCUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This function computes the number of bytes required to store
a NULL terminated oem string that is equivalent to the specified
unicode string. If an oem string can not be formed, the return value
is 0.
Arguments:
UnicodeString - Supplies a unicode string whose equivalent size as
an oem string is to be calculated.
Return Value:
0 - The operation failed, the unicode string can not be translated
into oem using the OEM code page therefore no storage is
needed for the oem string.
!0 - The operation was successful. The return value specifies the
number of bytes required to hold an NULL terminated oem string
equivalent to the specified unicode string.
--*/
{
ULONG cbMultiByteString;
RTL_PAGED_CODE();
//
// LATER: Define an RtlUnicodeToOemSize.
// In the Japanese version, it's safe to call
// RtlUnicodeToMultiByteSize because the Ansi code page
// and the OEM code page are the same.
//
//
// Get the size of the string - this call handles DBCS.
//
RtlUnicodeToMultiByteSize( &cbMultiByteString,
UnicodeString->Buffer,
UnicodeString->Length );
//
// Return the size in bytes.
//
return (cbMultiByteString + 1);
}
ULONG
RtlxAnsiStringToUnicodeSize(
IN PCANSI_STRING AnsiString
)
/*++
Routine Description:
This function computes the number of bytes required to store a NULL
terminated unicode string that is equivalent to the specified ansi
string.
Arguments:
AnsiString - Supplies an ansi string whose equivalent size as a
unicode string is to be calculated. The ansi string is
interpreted relative to the current system locale.
Return Value:
The return value specifies the number of bytes required to hold a
NULL terminated unicode string equivalent to the specified ansi
string.
--*/
{
ULONG cbConverted;
RTL_PAGED_CODE();
//
// Get the size of the string - this call handles DBCS.
//
RtlMultiByteToUnicodeSize( &cbConverted ,
AnsiString->Buffer,
AnsiString->Length );
//
// Return the size in bytes.
//
return ( cbConverted + sizeof(UNICODE_NULL) );
}
ULONG
RtlxOemStringToUnicodeSize(
IN PCOEM_STRING OemString
)
/*++
Routine Description:
This function computes the number of bytes required to store a NULL
terminated unicode string that is equivalent to the specified oem
string.
Arguments:
OemString - Supplies an oem string whose equivalent size as a
unicode string is to be calculated. The oem string is
interpreted relative to the current oem code page (OCP).
Return Value:
The return value specifies the number of bytes required to hold a
NULL terminated unicode string equivalent to the specified oem
string.
--*/
{
ULONG cbConverted;
RTL_PAGED_CODE();
//
// LATER: Define an RtlOemToUnicodeSize.
// In the Japanese version, it's safe to call
// RtlMultiByteToUnicodeSize because the Ansi code page
// and the OEM code page are the same.
//
//
// Get the size of the string - this call handles DBCS.
//
RtlMultiByteToUnicodeSize( &cbConverted,
OemString->Buffer,
OemString->Length );
//
// Return the size in bytes.
//
return ( cbConverted + sizeof(UNICODE_NULL) );
}
LONG
RtlCompareUnicodeString(
IN PCUNICODE_STRING String1,
IN PCUNICODE_STRING String2,
IN BOOLEAN CaseInSensitive
)
/*++
Routine Description:
The RtlCompareUnicodeString function compares two counted strings. The
return value indicates if the strings are equal or String1 is less than
String2 or String1 is greater than String2.
The CaseInSensitive parameter specifies if case is to be ignored when
doing the comparison.
Arguments:
String1 - Pointer to the first string.
String2 - Pointer to the second string.
CaseInsensitive - TRUE if case should be ignored when doing the
comparison.
Return Value:
Signed value that gives the results of the comparison:
Zero - String1 equals String2
< Zero - String1 less than String2
> Zero - String1 greater than String2
--*/
{
PCWSTR s1, s2, Limit;
LONG n1, n2;
WCHAR c1, c2;
RTL_PAGED_CODE();
s1 = String1->Buffer;
s2 = String2->Buffer;
n1 = String1->Length;
n2 = String2->Length;
ASSERT((n1 & 1) == 0);
ASSERT((n2 & 1) == 0);
ASSERT(!(((((ULONG_PTR)s1 & 1) != 0) || (((ULONG_PTR)s2 & 1) != 0)) && (n1 != 0) && (n2 != 0)));
Limit = (PWCHAR)((PCHAR)s1 + (n1 <= n2 ? n1 : n2));
if (CaseInSensitive) {
while (s1 < Limit) {
c1 = *s1++;
c2 = *s2++;
if (c1 != c2) {
//
// Note that this needs to reference the translation table!
//
c1 = NLS_UPCASE(c1);
c2 = NLS_UPCASE(c2);
if (c1 != c2) {
return (LONG)(c1) - (LONG)(c2);
}
}
}
} else {
while (s1 < Limit) {
c1 = *s1++;
c2 = *s2++;
if (c1 != c2) {
return (LONG)(c1) - (LONG)(c2);
}
}
}
return n1 - n2;
}
BOOLEAN
RtlEqualUnicodeString(
IN PCUNICODE_STRING String1,
IN PCUNICODE_STRING String2,
IN BOOLEAN CaseInSensitive
)
/*++
Routine Description:
The RtlEqualUnicodeString function compares two counted unicode strings for
equality.
The CaseInSensitive parameter specifies if case is to be ignored when
doing the comparison.
Arguments:
String1 - Pointer to the first string.
String2 - Pointer to the second string.
CaseInsensitive - TRUE if case should be ignored when doing the
comparison.
Return Value:
Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
--*/
{
PWCHAR s1, s2, Limit;
LONG n1, n2;
WCHAR c1, c2;
RTL_PAGED_CODE();
n1 = String1->Length;
n2 = String2->Length;
if (n1 == n2) {
s1 = String1->Buffer;
s2 = String2->Buffer;
Limit = (PWCHAR)((PCHAR)s1 + (n1&~(sizeof(WCHAR) - 1)));
if (CaseInSensitive) {
while (s1 < Limit) {
c1 = *s1++;
c2 = *s2++;
if ((c1 != c2) && (NLS_UPCASE(c1) != NLS_UPCASE(c2))) {
return FALSE;
}
}
return TRUE;
} else {
while (s1 < Limit) {
c1 = *s1++;
c2 = *s2++;
if (c1 != c2) {
return FALSE;
}
}
return TRUE;
}
} else {
return FALSE;
}
}
BOOLEAN
RtlPrefixUnicodeString(
IN PUNICODE_STRING String1,
IN PUNICODE_STRING String2,
IN BOOLEAN CaseInSensitive
)
/*++
Routine Description:
The RtlPrefixUnicodeString function determines if the String1
counted string parameter is a prefix of the String2 counted string
parameter.
The CaseInSensitive parameter specifies if case is to be ignored when
doing the comparison.
Arguments:
String1 - Pointer to the first unicode string.
String2 - Pointer to the second unicode string.
CaseInsensitive - TRUE if case should be ignored when doing the
comparison.
Return Value:
Boolean value that is TRUE if String1 equals a prefix of String2 and
FALSE otherwise.
--*/
{
PWSTR s1, s2;
ULONG n;
WCHAR c1, c2;
RTL_PAGED_CODE();
s1 = String1->Buffer;
s2 = String2->Buffer;
n = String1->Length;
if (String2->Length < n) {
return( FALSE );
}
n = n / sizeof(c1);
if (CaseInSensitive) {
while (n) {
c1 = *s1++;
c2 = *s2++;
if ((c1 != c2) && (NLS_UPCASE(c1) != NLS_UPCASE(c2))) {
return( FALSE );
}
n--;
}
}
else {
while (n) {
if (*s1++ != *s2++) {
return( FALSE );
}
n--;
}
}
return TRUE;
}
VOID
RtlCopyUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCUNICODE_STRING SourceString OPTIONAL
)
/*++
Routine Description:
The RtlCopyString function copies the SourceString to the
DestinationString. If SourceString is not specified, then
the Length field of DestinationString is set to zero. The
MaximumLength and Buffer fields of DestinationString are not
modified by this function.
The number of bytes copied from the SourceString is either the
Length of SourceString or the MaximumLength of DestinationString,
whichever is smaller.
Arguments:
DestinationString - Pointer to the destination string.
SourceString - Optional pointer to the source string.
Return Value:
None.
--*/
{
UNALIGNED WCHAR *src, *dst;
ULONG n;
if (ARGUMENT_PRESENT(SourceString)) {
dst = DestinationString->Buffer;
src = SourceString->Buffer;
n = SourceString->Length;
if ((USHORT)n > DestinationString->MaximumLength) {
n = DestinationString->MaximumLength;
}
DestinationString->Length = (USHORT)n;
RtlCopyMemory(dst, src, n);
if (DestinationString->Length < DestinationString->MaximumLength) {
dst[n / sizeof(WCHAR)] = UNICODE_NULL;
}
} else {
DestinationString->Length = 0;
}
return;
}
NTSTATUS
RtlAppendUnicodeToString (
IN PUNICODE_STRING Destination,
IN PCWSTR Source OPTIONAL
)
/*++
Routine Description:
This routine appends the supplied UNICODE string to an existing
PUNICODE_STRING.
It will copy bytes from the Source PSZ to the destination PSTRING up to
the destinations PUNICODE_STRING->MaximumLength field.
Arguments:
IN PUNICODE_STRING Destination, - Supplies a pointer to the destination
string
IN PWSTR Source - Supplies the string to append to the destination
Return Value:
STATUS_SUCCESS - The source string was successfully appended to the
destination counted string.
STATUS_BUFFER_TOO_SMALL - The destination string length was not big
enough to allow the source string to be appended. The Destination
string length is not updated.
--*/
{
USHORT n;
UNALIGNED WCHAR *dst;
if (ARGUMENT_PRESENT( Source )) {
UNICODE_STRING UniSource;
RtlInitUnicodeString(&UniSource, Source);
n = UniSource.Length;
if ((n + Destination->Length) > Destination->MaximumLength) {
return( STATUS_BUFFER_TOO_SMALL );
}
dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
RtlMoveMemory( dst, Source, n );
Destination->Length += n;
if (Destination->Length < Destination->MaximumLength) {
dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
}
}
return( STATUS_SUCCESS );
}
NTSTATUS
RtlAppendUnicodeStringToString (
IN OUT PUNICODE_STRING Destination,
IN PCUNICODE_STRING Source
)
/*++
Routine Description:
This routine will concatinate two PSTRINGs together. It will copy
bytes from the source up to the MaximumLength of the destination.
Arguments:
IN PSTRING Destination, - Supplies the destination string
IN PSTRING Source - Supplies the source for the string copy
Return Value:
STATUS_SUCCESS - The source string was successfully appended to the
destination counted string.
STATUS_BUFFER_TOO_SMALL - The destination string length was not big
enough to allow the source string to be appended. The Destination
string length is not updated.
--*/
{
USHORT n = Source->Length;
UNALIGNED WCHAR *dst;
if (n) {
if ((n + Destination->Length) > Destination->MaximumLength) {
return( STATUS_BUFFER_TOO_SMALL );
}
dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
RtlMoveMemory( dst, Source->Buffer, n );
Destination->Length += n;
if (Destination->Length < Destination->MaximumLength) {
dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
}
}
return( STATUS_SUCCESS );
}
BOOLEAN
RtlCreateUnicodeString(
OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
)
{
ULONG cb;
RTL_PAGED_CODE();
cb = (wcslen( SourceString ) + 1) * sizeof( WCHAR );
DestinationString->Buffer = (RtlAllocateStringRoutine)( cb );
if (DestinationString->Buffer) {
RtlCopyMemory( DestinationString->Buffer, SourceString, cb );
DestinationString->MaximumLength = (USHORT)cb;
DestinationString->Length = (USHORT)(cb - sizeof( UNICODE_NULL ));
return( TRUE );
}
else {
return( FALSE );
}
}
BOOLEAN
RtlEqualDomainName(
IN PCUNICODE_STRING String1,
IN PCUNICODE_STRING String2
)
/*++
Routine Description:
The RtlEqualDomainName function compares two domain names for equality.
The comparison is a case insensitive comparison of the OEM equivalent
strings.
The domain name is not validated for length nor invalid characters.
Arguments:
String1 - Pointer to the first string.
String2 - Pointer to the second string.
Return Value:
Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
--*/
{
NTSTATUS Status;
BOOLEAN ReturnValue = FALSE;
OEM_STRING OemString1;
OEM_STRING OemString2;
RTL_PAGED_CODE();
//
// Upper case and convert the first string to OEM
//
Status = RtlUpcaseUnicodeStringToOemString( &OemString1,
String1,
TRUE ); // Allocate Dest
if ( NT_SUCCESS( Status ) ) {
//
// Upper case and convert the second string to OEM
//
Status = RtlUpcaseUnicodeStringToOemString( &OemString2,
String2,
TRUE ); // Allocate Dest
if ( NT_SUCCESS( Status ) ) {
//
// Do a case insensitive comparison.
//
ReturnValue = RtlEqualString( &OemString1,
&OemString2,
FALSE );
RtlFreeOemString( &OemString2 );
}
RtlFreeOemString( &OemString1 );
}
return ReturnValue;
}
BOOLEAN
RtlEqualComputerName(
IN PCUNICODE_STRING String1,
IN PCUNICODE_STRING String2
)
/*++
Routine Description:
The RtlEqualComputerName function compares two computer names for equality.
The comparison is a case insensitive comparison of the OEM equivalent
strings.
The domain name is not validated for length nor invalid characters.
Arguments:
String1 - Pointer to the first string.
String2 - Pointer to the second string.
Return Value:
Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
--*/
{
return RtlEqualDomainName( String1, String2 );
}
/**
**/
#define UNICODE_FFFF 0xFFFF
#define REVERSE_BYTE_ORDER_MARK 0xFFFE
#define BYTE_ORDER_MARK 0xFEFF
#define PARAGRAPH_SEPARATOR 0x2029
#define LINE_SEPARATOR 0x2028
#define UNICODE_TAB 0x0009
#define UNICODE_LF 0x000A
#define UNICODE_CR 0x000D
#define UNICODE_SPACE 0x0020
#define UNICODE_CJK_SPACE 0x3000
#define UNICODE_R_TAB 0x0900
#define UNICODE_R_LF 0x0A00
#define UNICODE_R_CR 0x0D00
#define UNICODE_R_SPACE 0x2000
#define UNICODE_R_CJK_SPACE 0x0030 /* Ambiguous - same as ASCII '0' */
#define ASCII_CRLF 0x0A0D
#define __max(a,b) (((a) > (b)) ? (a) : (b))
#define __min(a,b) (((a) < (b)) ? (a) : (b))
BOOLEAN
RtlIsTextUnicode(
IN PVOID Buffer,
IN ULONG Size,
IN OUT PULONG Result OPTIONAL
)
/*++
Routine Description:
IsTextUnicode performs a series of inexpensive heuristic checks
on a buffer in order to verify that it contains Unicode data.
[[ need to fix this section, see at the end ]]
Found Return Result
BOM TRUE BOM
RBOM FALSE RBOM
FFFF FALSE Binary
NULL FALSE Binary
null TRUE null bytes
ASCII_CRLF FALSE CRLF
UNICODE_TAB etc. TRUE Zero Ext Controls
UNICODE_TAB_R FALSE Reversed Controls
UNICODE_ZW etc. TRUE Unicode specials
1/3 as little variation in hi-byte as in lo byte: TRUE Correl
3/1 or worse " FALSE AntiCorrel
Arguments:
Buffer - pointer to buffer containing text to examine.
Size - size of buffer in bytes. At most 256 characters in this will
be examined. If the size is less than the size of a unicode
character, then this function returns FALSE.
Result - optional pointer to a flag word that contains additional information
about the reason for the return value. If specified, this value on
input is a mask that is used to limit the factors this routine uses
to make its decision. On output, this flag word is set to contain
those flags that were used to make its decision.
Return Value:
Boolean value that is TRUE if Buffer contains unicode characters.
--*/
{
UNALIGNED WCHAR *lpBuff = Buffer;
PUCHAR lpb = Buffer;
ULONG iBOM = 0;
ULONG iCR = 0;
ULONG iLF = 0;
ULONG iTAB = 0;
ULONG iSPACE = 0;
ULONG iCJK_SPACE = 0;
ULONG iFFFF = 0;
ULONG iPS = 0;
ULONG iLS = 0;
ULONG iRBOM = 0;
ULONG iR_CR = 0;
ULONG iR_LF = 0;
ULONG iR_TAB = 0;
ULONG iR_SPACE = 0;
ULONG iNull = 0;
ULONG iUNULL = 0;
ULONG iCRLF = 0;
ULONG iTmp;
ULONG LastLo = 0;
ULONG LastHi = 0;
ULONG iHi, iLo;
ULONG HiDiff = 0;
ULONG LoDiff = 0;
ULONG cLeadByte = 0;
ULONG cWeird = 0;
ULONG iResult = 0;
ULONG iMaxTmp = __min(256, Size / sizeof(WCHAR));
//
// Special case when the size is less than or equal to 2.
// Make sure we don't have a character followed by a null byte.
//
if ((Size < 2) ||
((Size == 2) && (lpBuff[0] != 0) && (lpb[1] == 0)))
{
if (ARGUMENT_PRESENT(Result))
{
*Result = IS_TEXT_UNICODE_ASCII16 | IS_TEXT_UNICODE_CONTROLS;
}
return (FALSE);
}
else if ((Size > 2) && ((Size / sizeof(WCHAR)) <= 256))
{
//
// If the Size passed in is an even number, we don't want to
// use the last WCHAR because it will contain the final null
// byte.
//
if (((Size % sizeof(WCHAR)) == 0) &&
((lpBuff[iMaxTmp - 1] & 0xff00) == 0))
{
iMaxTmp--;
}
}
//
// Check at most 256 wide characters, collect various statistics.
//
for (iTmp = 0; iTmp < iMaxTmp; iTmp++)
{
switch (lpBuff[iTmp])
{
case BYTE_ORDER_MARK:
iBOM++;
break;
case PARAGRAPH_SEPARATOR:
iPS++;
break;
case LINE_SEPARATOR:
iLS++;
break;
case UNICODE_LF:
iLF++;
break;
case UNICODE_TAB:
iTAB++;
break;
case UNICODE_SPACE:
iSPACE++;
break;
case UNICODE_CJK_SPACE:
iCJK_SPACE++;
break;
case UNICODE_CR:
iCR++;
break;
//
// The following codes are expected to show up in
// byte reversed files.
//
case REVERSE_BYTE_ORDER_MARK:
iRBOM++;
break;
case UNICODE_R_LF:
iR_LF++;
break;
case UNICODE_R_TAB:
iR_TAB++;
break;
case UNICODE_R_CR:
iR_CR++;
break;
case UNICODE_R_SPACE:
iR_SPACE++;
break;
//
// The following codes are illegal and should never occur.
//
case UNICODE_FFFF:
iFFFF++;
break;
case UNICODE_NULL:
iUNULL++;
break;
//
// The following is not currently a Unicode character
// but is expected to show up accidentally when reading
// in ASCII files which use CRLF on a little endian machine.
//
case ASCII_CRLF:
iCRLF++;
break; /* little endian */
}
//
// Collect statistics on the fluctuations of high bytes
// versus low bytes.
//
iHi = HIBYTE(lpBuff[iTmp]);
iLo = LOBYTE(lpBuff[iTmp]);
//
// Count cr/lf and lf/cr that cross two words.
//
if ((iLo == '\r' && LastHi == '\n') ||
(iLo == '\n' && LastHi == '\r'))
{
cWeird++;
}
iNull += (iHi ? 0 : 1) + (iLo ? 0 : 1); /* count Null bytes */
HiDiff += __max(iHi, LastHi) - __min(LastHi, iHi);
LoDiff += __max(iLo, LastLo) - __min(LastLo, iLo);
LastLo = iLo;
LastHi = iHi;
}
//
// Count cr/lf and lf/cr that cross two words.
//
if ((iLo == '\r' && LastHi == '\n') ||
(iLo == '\n' && LastHi == '\r'))
{
cWeird++;
}
if (iHi == '\0') /* don't count the last null */
iNull--;
if (iHi == 26) /* count ^Z at end as weird */
cWeird++;
iMaxTmp = __min(256 * sizeof(WCHAR), Size);
if (NlsMbCodePageTag)
{
for (iTmp = 0; iTmp < iMaxTmp; iTmp++)
{
if (NlsLeadByteInfo[lpb[iTmp]])
{
cLeadByte++;
iTmp++; /* should check for trailing-byte range */
}
}
}
//
// Sift through the statistical evidence.
//
if (LoDiff < 127 && HiDiff == 0)
{
iResult |= IS_TEXT_UNICODE_ASCII16; /* likely 16-bit ASCII */
}
if (HiDiff && LoDiff == 0)
{
iResult |= IS_TEXT_UNICODE_REVERSE_ASCII16; /* reverse 16-bit ASCII */
}
//
// Use leadbyte info to weight statistics.
//
if (!NlsMbCodePageTag || cLeadByte == 0 ||
!ARGUMENT_PRESENT(Result) || !(*Result & IS_TEXT_UNICODE_DBCS_LEADBYTE))
{
iHi = 3;
}
else
{
//
// A ratio of cLeadByte:cb of 1:2 ==> dbcs
// Very crude - should have a nice eq.
//
iHi = __min(256, Size / sizeof(WCHAR)) / 2;
if (cLeadByte < (iHi - 1) / 3)
{
iHi = 3;
}
else if (cLeadByte < (2 * (iHi - 1)) / 3)
{
iHi = 2;
}
else
{
iHi = 1;
}
iResult |= IS_TEXT_UNICODE_DBCS_LEADBYTE;
}
if (iHi * HiDiff < LoDiff)
{
iResult |= IS_TEXT_UNICODE_STATISTICS;
}
if (iHi * LoDiff < HiDiff)
{
iResult |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
}
//
// Any control codes widened to 16 bits? Any Unicode character
// which contain one byte in the control code range?
//
if (iCR + iLF + iTAB + iSPACE + iCJK_SPACE /*+iPS+iLS*/)
{
iResult |= IS_TEXT_UNICODE_CONTROLS;
}
if (iR_LF + iR_CR + iR_TAB + iR_SPACE)
{
iResult |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
}
//
// Any characters that are illegal for Unicode?
//
if ((iRBOM + iFFFF + iUNULL + iCRLF) != 0 ||
(cWeird != 0 && cWeird >= iMaxTmp/40))
{
iResult |= IS_TEXT_UNICODE_ILLEGAL_CHARS;
}
//
// Odd buffer length cannot be Unicode.
//
if (Size & 1)
{
iResult |= IS_TEXT_UNICODE_ODD_LENGTH;
}
//
// Any NULL bytes? (Illegal in ANSI)
//
if (iNull)
{
iResult |= IS_TEXT_UNICODE_NULL_BYTES;
}
//
// POSITIVE evidence, BOM or RBOM used as signature.
//
if (*lpBuff == BYTE_ORDER_MARK)
{
iResult |= IS_TEXT_UNICODE_SIGNATURE;
}
else if (*lpBuff == REVERSE_BYTE_ORDER_MARK)
{
iResult |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
}
//
// Limit to desired categories if requested.
//
if (ARGUMENT_PRESENT(Result))
{
iResult &= *Result;
*Result = iResult;
}
//
// There are four separate conclusions:
//
// 1: The file APPEARS to be Unicode AU
// 2: The file CANNOT be Unicode CU
// 3: The file CANNOT be ANSI CA
//
//
// This gives the following possible results
//
// CU
// + -
//
// AU AU
// + - + -
// -------- --------
// CA +| 0 0 2 3
// |
// -| 1 1 4 5
//
//
// Note that there are only 6 really different cases, not 8.
//
// 0 - This must be a binary file
// 1 - ANSI file
// 2 - Unicode file (High probability)
// 3 - Unicode file (more than 50% chance)
// 5 - No evidence for Unicode (ANSI is default)
//
// The whole thing is more complicated if we allow the assumption
// of reverse polarity input. At this point we have a simplistic
// model: some of the reverse Unicode evidence is very strong,
// we ignore most weak evidence except statistics. If this kind of
// strong evidence is found together with Unicode evidence, it means
// its likely NOT Text at all. Furthermore if a REVERSE_BYTE_ORDER_MARK
// is found, it precludes normal Unicode. If both byte order marks are
// found it's not Unicode.
//
//
// Unicode signature : uncontested signature outweighs reverse evidence.
//
if ((iResult & IS_TEXT_UNICODE_SIGNATURE) &&
!(iResult & (IS_TEXT_UNICODE_NOT_UNICODE_MASK&(~IS_TEXT_UNICODE_DBCS_LEADBYTE))))
{
return (TRUE);
}
//
// If we have conflicting evidence, it's not Unicode.
//
if (iResult & IS_TEXT_UNICODE_REVERSE_MASK)
{
return (FALSE);
}
//
// Statistical and other results (cases 2 and 3).
//
if (!(iResult & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
((iResult & IS_TEXT_UNICODE_NOT_ASCII_MASK) ||
(iResult & IS_TEXT_UNICODE_UNICODE_MASK)))
{
return (TRUE);
}
return (FALSE);
}
NTSTATUS
RtlDnsHostNameToComputerName(
OUT PUNICODE_STRING ComputerNameString,
IN PCUNICODE_STRING DnsHostNameString,
IN BOOLEAN AllocateComputerNameString
)
/*++
Routine Description:
The RtlDnsHostNameToComputerName API converts a DNS-style host name to a
Netbios-style computer name.
This API does a syntactical mapping of the name. As such, it should not
be used to convert a DNS domain name to a Netbios domain name.
There is no syntactical mapping for domain names.
DNS-style names consist of one or more "labels" separated by a period
(e.g., xxx.nt.microsoft.com). Each label can be up to 63 bytes of
UTF-8 characters and must consist only of characters specified
by the DnsValidateDnsName API. Upper and lower case characters are treated
as the same character. DNS names are represented in the UTF-8 character set
or UNICODE.
Netbios computer names consist of up to 15 bytes of OEM characters
including letters, digits, hyphens, periods and various other characters.
Some of these characters are specific to the character set. Netbios names
are typically represented in the OEM character set. The OEM character
set is different depending on the locale of the particular version of the OS
(e.g., the German version has a different character set than the US version).
Some OEM character sets represent certain characters as 2 bytes
(e.g., Japanese). Netbios names, by convention, are represented in
uppercase where the translation algorithm from lowercase to uppercase
is OEM character set dependent.
These characteristics make translating between DNS name and Netbios name
difficult.
RtlDnsHostNameToComputerName enforces a textual convention for
mapping between the two names. This convention limits the names of
computers to be the common subset of the names. Specifically, the leftmost
label of the DNS name is truncated to 15-bytes of OEM characters.
As such, RtlDnsHostNameToComputerName simply interprets the leftmost label
of the DNS name as the Netbios name. If the DNS name doesn't meet the
criteria of a valid translatable name, a distinct error code is returned.
Arguments:
ComputerNameString - Returns a unicode string that is equivalent to
the DNS source string. The maximum length field is only
set if AllocateComputerNameString is TRUE.
DnsHostNameString - Supplies the DNS host name source string that is to be
converted to a netbios computer name.
This routine does NOT attempt to validate that the passed in DnsHostNameString
is a valid DNS host a DNS host name. Rather it assumes that the passed in
name is valid and converts it on a best effort basis.
AllocateComputerNameString - Supplies a flag that controls whether or
not this API allocates the buffer space for the destination
string. If it does, then the buffer must be deallocated using
RtlFreeUnicodeString (note that only storage for
DestinationString->Buffer is allocated by this API).
Return Value:
SUCCESS - The conversion was successful
STATUS_NO_MEMORY - There is not enough memory to allocate the return buffer.
STATUS_INVALID_COMPUTER_NAME - The DnsHostName has no first label or
one or more characters of the DnsHostName could not be converted to
the OEM character set.
--*/
{
NTSTATUS Status;
UNICODE_STRING LocalDnsHostNameString;
OEM_STRING OemString;
ULONG ActualOemLength;
CHAR OemStringBuffer[16];
ULONG i;
RTL_PAGED_CODE();
//
// Truncate the dns name to the first label
//
LocalDnsHostNameString = *DnsHostNameString;
for ( i=0; i<LocalDnsHostNameString.Length/sizeof(WCHAR); i++ ) {
if ( LocalDnsHostNameString.Buffer[i] == L'.' ) {
LocalDnsHostNameString.Length = (USHORT)(i * sizeof(WCHAR));
break;
}
}
if ( LocalDnsHostNameString.Length < sizeof(WCHAR) ) {
return STATUS_INVALID_COMPUTER_NAME;
}
//
// Convert the DNS name to OEM truncating at 15 OEM bytes.
//
Status = RtlUpcaseUnicodeToOemN(
OemStringBuffer,
NETBIOS_NAME_LEN-1, // truncate to 15 bytes
&ActualOemLength,
LocalDnsHostNameString.Buffer,
LocalDnsHostNameString.Length );
if ( !NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW ) {
return Status;
}
//
// Check to see if any characters are not valid OEM characters.
//
OemString.Buffer = OemStringBuffer;
OemString.MaximumLength = OemString.Length = (USHORT) ActualOemLength;
if ( !RtlpDidUnicodeToOemWork( &OemString, &LocalDnsHostNameString )) {
return STATUS_INVALID_COMPUTER_NAME;
}
//
// Convert the OEM string back to UNICODE
//
Status = RtlOemStringToUnicodeString(
ComputerNameString,
&OemString,
AllocateComputerNameString );
if ( !NT_SUCCESS(Status) ) {
return Status;
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlHashUnicodeString(
const UNICODE_STRING *String,
BOOLEAN CaseInSensitive,
ULONG HashAlgorithm,
PULONG HashValue
)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG TmpHashValue = 0;
ULONG Chars;
PCWSTR Buffer;
if ((String == NULL) ||
(HashValue == NULL))
{
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Buffer = String->Buffer;
*HashValue = 0;
Chars = String->Length / sizeof(WCHAR);
switch (HashAlgorithm)
{
default:
Status = STATUS_INVALID_PARAMETER;
goto Exit;
break;
case HASH_STRING_ALGORITHM_DEFAULT:
case HASH_STRING_ALGORITHM_X65599:
if (CaseInSensitive)
{
while (Chars-- != 0)
{
WCHAR Char = *Buffer++;
TmpHashValue = (TmpHashValue * 65599) + NLS_UPCASE(Char);
}
}
else
{
while (Chars-- != 0)
TmpHashValue = (TmpHashValue * 65599) + *Buffer++;
}
break;
}
*HashValue = TmpHashValue;
Status = STATUS_SUCCESS;
Exit:
return Status;
}
NTSTATUS
RtlValidateUnicodeString(
ULONG Flags,
const UNICODE_STRING *String
)
{
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(Flags == 0);
if (Flags != 0) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (String != NULL) {
if (((String->Length % 2) != 0) ||
((String->MaximumLength % 2) != 0) ||
(String->Length > String->MaximumLength)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (((String->Length != 0) ||
(String->MaximumLength != 0)) &&
(String->Buffer == NULL)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
}
Status = STATUS_SUCCESS;
Exit:
return Status;
}
NTSTATUS
RtlDuplicateUnicodeString(
ULONG Flags,
PCUNICODE_STRING StringIn,
PUNICODE_STRING StringOut
)
{
NTSTATUS Status = STATUS_SUCCESS;
USHORT Length = 0;
USHORT NewMaximumLength = 0;
PWSTR Buffer = NULL;
if (((Flags & ~(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)) != 0) ||
(StringOut == NULL)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
// It doesn't make sense to force allocation of a null string unless you
// want null termination.
if ((Flags & RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING) &&
!(Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Status = RtlValidateUnicodeString(0, StringIn);
if (!NT_SUCCESS(Status))
goto Exit;
if (StringIn != NULL)
Length = StringIn->Length;
if ((Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) &&
(Length == UNICODE_STRING_MAX_BYTES)) {
Status = STATUS_NAME_TOO_LONG;
goto Exit;
}
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
NewMaximumLength = (USHORT) (Length + sizeof(WCHAR));
else
NewMaximumLength = Length;
// If it's a zero length string in, force the allocation length to zero
// unless the caller said that they want zero length strings allocated.
if (((Flags & RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING) == 0) &&
(Length == 0)) {
NewMaximumLength = 0;
}
if (NewMaximumLength != 0) {
Buffer = (RtlAllocateStringRoutine)(NewMaximumLength);
if (Buffer == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
// If there's anything to copy, copy it. We explicitly test Length because
// StringIn could be a NULL pointer, so dereferencing it to get the Buffer
// pointer would access violate.
if (Length != 0) {
RtlCopyMemory(
Buffer,
StringIn->Buffer,
Length);
}
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) {
Buffer[Length / sizeof(WCHAR)] = L'\0';
}
}
StringOut->Buffer = Buffer;
StringOut->MaximumLength = NewMaximumLength;
StringOut->Length = Length;
Status = STATUS_SUCCESS;
Exit:
return Status;
}
NTSTATUS
RtlFindCharInUnicodeString(
ULONG Flags,
PCUNICODE_STRING StringToSearch,
PCUNICODE_STRING CharSet,
USHORT *NonInclusivePrefixLength
)
{
NTSTATUS Status;
USHORT PrefixLengthFound = 0;
USHORT CharsToSearch = 0;
int MovementDirection = 0;
PCWSTR Cursor = NULL;
BOOLEAN Found = FALSE;
USHORT CharSetChars = 0;
PCWSTR CharSetBuffer = NULL;
USHORT i;
if (NonInclusivePrefixLength != 0)
*NonInclusivePrefixLength = 0;
if (((Flags & ~(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END |
RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET |
RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE)) != 0) ||
(NonInclusivePrefixLength == NULL)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Status = RtlValidateUnicodeString(0, StringToSearch);
if (!NT_SUCCESS(Status))
goto Exit;
Status = RtlValidateUnicodeString(0, CharSet);
if (!NT_SUCCESS(Status))
goto Exit;
CharsToSearch = StringToSearch->Length / sizeof(WCHAR);
CharSetChars = CharSet->Length / sizeof(WCHAR);
CharSetBuffer = CharSet->Buffer;
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END) {
MovementDirection = -1;
Cursor = StringToSearch->Buffer + CharsToSearch - 1;
} else {
MovementDirection = 1;
Cursor = StringToSearch->Buffer;
}
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE) {
// Unicode standard says to always do case insensitive comparisons in lower case since the case mappings are
// asymmetric.
WCHAR CharSetStackBuffer[32]; // optimized pre-downcased for case insensitive
// Optimization for the case of a relatively small char set to match
if (CharSetChars <= RTL_NUMBER_OF(CharSetStackBuffer)) {
for (i=0; i<CharSetChars; i++)
CharSetStackBuffer[i] = RtlDowncaseUnicodeChar(CharSetBuffer[i]);
while (CharsToSearch != 0) {
const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetStackBuffer[i])
break;
}
if (i == CharSetChars)
break;
} else {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetStackBuffer[i])
break;
}
if (i != CharSetChars)
break;
}
CharsToSearch--;
Cursor += MovementDirection;
}
} else {
while (CharsToSearch != 0) {
const WCHAR wch = RtlDowncaseUnicodeChar(*Cursor);
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
for (i=0; i<CharSetChars; i++) {
if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
break;
}
}
if (i == CharSetChars)
break;
} else {
for (i=0; i<CharSetChars; i++) {
if (wch == RtlDowncaseUnicodeChar(CharSetBuffer[i])) {
break;
}
}
if (i != CharSetChars)
break;
}
CharsToSearch--;
Cursor += MovementDirection;
}
}
} else {
if (CharSetChars == 1) {
// Significant optimization for looking for one character.
const WCHAR wchSearchChar = CharSetBuffer[0];
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
while (CharsToSearch != 0) {
if (*Cursor != wchSearchChar)
break;
CharsToSearch--;
Cursor += MovementDirection;
}
} else {
while (CharsToSearch != 0) {
if (*Cursor == wchSearchChar)
break;
CharsToSearch--;
Cursor += MovementDirection;
}
}
} else {
while (CharsToSearch != 0) {
const WCHAR wch = *Cursor;
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET) {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetBuffer[i])
break;
}
if (i == CharSetChars)
break;
} else {
for (i=0; i<CharSetChars; i++) {
if (wch == CharSetBuffer[i])
break;
}
if (i != CharSetChars)
break;
}
CharsToSearch--;
Cursor += MovementDirection;
}
}
}
if (CharsToSearch == 0) {
Status = STATUS_NOT_FOUND;
goto Exit;
}
CharsToSearch--;
if (Flags & RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END)
PrefixLengthFound = (USHORT) (CharsToSearch * sizeof(WCHAR));
else
PrefixLengthFound = (USHORT) (StringToSearch->Length - (CharsToSearch * sizeof(WCHAR)));
*NonInclusivePrefixLength = PrefixLengthFound;
Status = STATUS_SUCCESS;
Exit:
return Status;
}
NTSTATUS
NTAPI
RtlFindAndReplaceCharacterInString(
ULONG Flags,
PVOID Reserved,
PUNICODE_STRING String,
WCHAR Find,
WCHAR Replace
)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG Index = 0;
ULONG Length = 0;
typedef WCHAR TChar;
if (Flags & ~RTL_FIND_AND_REPLACE_CHARACTER_IN_STRING_CASE_SENSITIVE) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (Reserved != NULL) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (String == NULL
|| Find == Replace
) {
Status = STATUS_SUCCESS;
goto Exit;
}
Length = RTL_STRING_GET_LENGTH_CHARS(String);
if (Length == 0) {
Status = STATUS_SUCCESS;
goto Exit;
}
if ((Flags & RTL_FIND_AND_REPLACE_CHARACTER_IN_STRING_CASE_SENSITIVE) != 0) {
for (Index = 0 ; Index != Length ; ++Index) {
if ( String->Buffer[Index] == Find
) {
String->Buffer[Index] = Replace;
}
}
}
else {
TChar DownFind = RtlDowncaseUnicodeChar(Find);
TChar UpFind = RtlUpcaseUnicodeChar(Find);
for (Index = 0 ; Index != Length ; ++Index) {
const TChar Char = String->Buffer[Index];
if ( Char == Find
|| Char == UpFind
|| Char == DownFind
) {
String->Buffer[Index] = Replace;
}
else {
TChar DownChar = RtlDowncaseUnicodeChar(Char);
if ( DownChar == Find
//|| DownChar == UpFind // presumably not possible
|| DownChar == DownFind
) {
String->Buffer[Index] = Replace;
}
else if (DownChar != Char) {
TChar UpChar = RtlUpcaseUnicodeChar(Char);
if ( UpChar == Find
|| UpChar == UpFind
//||UpChar == DownFind // presumably not possible
) {
String->Buffer[Index] = Replace;
}
}
}
}
}
Status = STATUS_SUCCESS;
Exit:
return Status;
}