mirror of https://github.com/tongzx/nt5src
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
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;
|
|
}
|