832 lines
19 KiB
C
832 lines
19 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
strings.c
|
||
|
||
Abstract:
|
||
|
||
This module defines functions for manipulating counted strings (STRING).
|
||
A counted string is a data structure containing three fields. The Buffer
|
||
field is a pointer to the string itself. The MaximumLength field contains
|
||
the maximum number of bytes that can be stored in the memory pointed to
|
||
by the Buffer field. The Length field contains the current length, in
|
||
bytes, of the string pointed to by the Buffer field. Users of counted
|
||
strings should not make any assumptions about the existence of a null
|
||
byte at the end of the string, unless the null byte is explicitly
|
||
included in the Length of the string.
|
||
|
||
Author:
|
||
|
||
Steve Wood (stevewo) 31-Mar-1989
|
||
|
||
Revision History:
|
||
|
||
22-Sep-1993 JulieB Fixed TO_UPPER macro for chars above 0x7f.
|
||
|
||
|
||
--*/
|
||
|
||
#include "string.h"
|
||
#include "nt.h"
|
||
#include "ntrtlp.h"
|
||
|
||
|
||
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
|
||
//#pragma alloc_text(NONPAGE,RtlInitString)
|
||
//#pragma alloc_text(NONPAGE,RtlInitAnsiString)
|
||
//#pragma alloc_text(NONPAGE,RtlInitUnicodeString)
|
||
#pragma alloc_text(PAGE,RtlUpperChar)
|
||
#pragma alloc_text(PAGE,RtlCompareString)
|
||
#pragma alloc_text(PAGE,RtlPrefixString)
|
||
#pragma alloc_text(PAGE,RtlCreateUnicodeStringFromAsciiz)
|
||
#pragma alloc_text(PAGE,RtlUpperString)
|
||
#pragma alloc_text(PAGE,RtlAppendAsciizToString)
|
||
#pragma alloc_text(PAGE,RtlAppendStringToString)
|
||
#endif
|
||
|
||
//
|
||
// Global data used for translations.
|
||
//
|
||
extern PUSHORT NlsAnsiToUnicodeData; // Ansi CP to Unicode translation table
|
||
extern PCH NlsUnicodeToAnsiData; // Unicode to Ansi CP translation table
|
||
extern const PUSHORT NlsLeadByteInfo; // Lead byte info for ACP
|
||
extern PUSHORT NlsUnicodeToMbAnsiData; // Unicode to Multibyte Ansi CP translation table
|
||
extern BOOLEAN NlsMbCodePageTag; // TRUE -> Multibyte ACP, FALSE -> Singlebyte ACP
|
||
|
||
|
||
|
||
#if !defined(_M_IX86)
|
||
|
||
VOID
|
||
RtlInitString(
|
||
OUT PSTRING DestinationString,
|
||
IN PCSZ SourceString OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlInitString function initializes an NT counted string.
|
||
The DestinationString is initialized to point to the SourceString
|
||
and the Length and MaximumLength fields of DestinationString are
|
||
initialized to the length of the SourceString, which is zero if
|
||
SourceString is not specified.
|
||
|
||
Arguments:
|
||
|
||
DestinationString - Pointer to the counted string to initialize
|
||
|
||
SourceString - Optional pointer to a null terminated string that
|
||
the counted string is to point to.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Length;
|
||
|
||
DestinationString->Buffer = (PCHAR)SourceString;
|
||
if (ARGUMENT_PRESENT( SourceString )) {
|
||
Length = strlen(SourceString);
|
||
DestinationString->Length = (USHORT)Length;
|
||
DestinationString->MaximumLength = (USHORT)(Length+1);
|
||
}
|
||
else {
|
||
DestinationString->Length = 0;
|
||
DestinationString->MaximumLength = 0;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
RtlInitAnsiString(
|
||
OUT PANSI_STRING DestinationString,
|
||
IN PCSZ SourceString OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlInitAnsiString function initializes an NT counted string.
|
||
The DestinationString is initialized to point to the SourceString
|
||
and the Length and MaximumLength fields of DestinationString are
|
||
initialized to the length of the SourceString, which is zero if
|
||
SourceString is not specified.
|
||
|
||
Arguments:
|
||
|
||
DestinationString - Pointer to the counted string to initialize
|
||
|
||
SourceString - Optional pointer to a null terminated string that
|
||
the counted string is to point to.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Length;
|
||
|
||
DestinationString->Buffer = (PCHAR)SourceString;
|
||
if (ARGUMENT_PRESENT( SourceString )) {
|
||
Length = strlen(SourceString);
|
||
DestinationString->Length = (USHORT)Length;
|
||
DestinationString->MaximumLength = (USHORT)(Length+1);
|
||
}
|
||
else {
|
||
DestinationString->Length = 0;
|
||
DestinationString->MaximumLength = 0;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
RtlInitUnicodeString(
|
||
OUT PUNICODE_STRING DestinationString,
|
||
IN PCWSTR SourceString OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlInitUnicodeString function initializes an NT counted
|
||
unicode string. The DestinationString is initialized to point to
|
||
the SourceString and the Length and MaximumLength fields of
|
||
DestinationString are initialized to the length of the SourceString,
|
||
which is zero if SourceString is not specified.
|
||
|
||
Arguments:
|
||
|
||
DestinationString - Pointer to the counted string to initialize
|
||
|
||
SourceString - Optional pointer to a null terminated unicode string that
|
||
the counted string is to point to.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Length;
|
||
|
||
DestinationString->Buffer = (PWSTR)SourceString;
|
||
if (ARGUMENT_PRESENT( SourceString )) {
|
||
Length = wcslen( SourceString ) * sizeof( WCHAR );
|
||
DestinationString->Length = (USHORT)Length;
|
||
DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
|
||
}
|
||
else {
|
||
DestinationString->MaximumLength = 0;
|
||
DestinationString->Length = 0;
|
||
}
|
||
}
|
||
|
||
#endif // !defined(_M_IX86)
|
||
|
||
NTSTATUS
|
||
RtlInitUnicodeStringEx(
|
||
OUT PUNICODE_STRING DestinationString,
|
||
IN PCWSTR SourceString OPTIONAL
|
||
)
|
||
{
|
||
if (SourceString != NULL) {
|
||
SIZE_T Length = wcslen(SourceString);
|
||
|
||
// We are actually limited to 32765 characters since we want to store a meaningful
|
||
// MaximumLength also.
|
||
if (Length > (UNICODE_STRING_MAX_CHARS - 1)) {
|
||
return STATUS_NAME_TOO_LONG;
|
||
}
|
||
|
||
Length *= sizeof(WCHAR);
|
||
|
||
DestinationString->Length = (USHORT) Length;
|
||
DestinationString->MaximumLength = (USHORT) (Length + sizeof(WCHAR));
|
||
DestinationString->Buffer = (PWSTR) SourceString;
|
||
} else {
|
||
DestinationString->Length = 0;
|
||
DestinationString->MaximumLength = 0;
|
||
DestinationString->Buffer = NULL;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
RtlCopyString(
|
||
OUT PSTRING DestinationString,
|
||
IN const 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSZ 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;
|
||
while (n) {
|
||
*dst++ = *src++;
|
||
n--;
|
||
}
|
||
}
|
||
else {
|
||
DestinationString->Length = 0;
|
||
}
|
||
}
|
||
|
||
CHAR
|
||
RtlUpperChar (
|
||
register IN CHAR Character
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a character uppercased
|
||
.
|
||
Arguments:
|
||
|
||
IN CHAR Character - Supplies the character to upper case
|
||
|
||
Return Value:
|
||
|
||
CHAR - Uppercased version of the charac
|
||
ter
|
||
--*/
|
||
|
||
{
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
//
|
||
// NOTE: This assumes an ANSI string and it does NOT upper case
|
||
// DOUBLE BYTE characters properly.
|
||
//
|
||
|
||
//
|
||
// Handle a - z separately.
|
||
//
|
||
if (Character <= 'z') {
|
||
if (Character >= 'a') {
|
||
return Character ^ 0x20;
|
||
}
|
||
else {
|
||
return Character;
|
||
}
|
||
}
|
||
else {
|
||
WCHAR wCh;
|
||
|
||
/*
|
||
* Handle extended characters.
|
||
*/
|
||
if (!NlsMbCodePageTag) {
|
||
//
|
||
// Single byte code page.
|
||
//
|
||
wCh = NlsAnsiToUnicodeData[(UCHAR)Character];
|
||
wCh = NLS_UPCASE(wCh);
|
||
return NlsUnicodeToAnsiData[(USHORT)wCh];
|
||
}
|
||
else {
|
||
//
|
||
// Multi byte code page. Do nothing to the character
|
||
// if it's a lead byte or if the translation of the
|
||
// upper case Unicode character is a DBCS character.
|
||
//
|
||
if (!NlsLeadByteInfo[Character]) {
|
||
wCh = NlsAnsiToUnicodeData[(UCHAR)Character];
|
||
wCh = NLS_UPCASE(wCh);
|
||
wCh = NlsUnicodeToMbAnsiData[(USHORT)wCh];
|
||
if (!HIBYTE(wCh)) {
|
||
return LOBYTE(wCh);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return Character;
|
||
}
|
||
|
||
LONG
|
||
RtlCompareString(
|
||
IN const STRING *String1,
|
||
IN const STRING *String2,
|
||
IN BOOLEAN CaseInSensitive
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlCompareString 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
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PUCHAR s1, s2, Limit;
|
||
LONG n1, n2;
|
||
UCHAR c1, c2;
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
s1 = String1->Buffer;
|
||
s2 = String2->Buffer;
|
||
n1 = String1->Length;
|
||
n2 = String2->Length;
|
||
Limit = s1 + (n1 <= n2 ? n1 : n2);
|
||
if (CaseInSensitive) {
|
||
while (s1 < Limit) {
|
||
c1 = *s1++;
|
||
c2 = *s2++;
|
||
if (c1 !=c2) {
|
||
c1 = RtlUpperChar(c1);
|
||
c2 = RtlUpperChar(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
|
||
RtlEqualString(
|
||
IN const STRING *String1,
|
||
IN const STRING *String2,
|
||
IN BOOLEAN CaseInSensitive
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlEqualString function compares two counted 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PUCHAR s1, s2, Limit;
|
||
LONG n1, n2;
|
||
UCHAR c1, c2;
|
||
|
||
n1 = String1->Length;
|
||
n2 = String2->Length;
|
||
if (n1 == n2) {
|
||
s1 = String1->Buffer;
|
||
s2 = String2->Buffer;
|
||
Limit = s1 + n1;
|
||
if (CaseInSensitive) {
|
||
while (s1 < Limit) {
|
||
c1 = *s1++;
|
||
c2 = *s2++;
|
||
if (c1 != c2) {
|
||
c1 = RtlUpperChar(c1);
|
||
c2 = RtlUpperChar(c2);
|
||
if (c1 != c2) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
while (s1 < Limit) {
|
||
c1 = *s1++;
|
||
c2 = *s2++;
|
||
if (c1 != c2) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
RtlPrefixString(
|
||
IN PSTRING String1,
|
||
IN PSTRING String2,
|
||
IN BOOLEAN CaseInSensitive
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlPrefixString 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 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 a prefix of String2 and
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSZ s1, s2;
|
||
USHORT n;
|
||
UCHAR c1, c2;
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
s1 = String1->Buffer;
|
||
s2 = String2->Buffer;
|
||
n = String1->Length;
|
||
if (String2->Length < n) {
|
||
return( FALSE );
|
||
}
|
||
|
||
if (CaseInSensitive) {
|
||
while (n) {
|
||
c1 = *s1++;
|
||
c2 = *s2++;
|
||
|
||
if (c1 != c2 && RtlUpperChar(c1) != RtlUpperChar(c2)) {
|
||
return( FALSE );
|
||
}
|
||
|
||
n--;
|
||
}
|
||
}
|
||
else {
|
||
while (n) {
|
||
if (*s1++ != *s2++) {
|
||
return( FALSE );
|
||
}
|
||
|
||
n--;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
RtlCreateUnicodeStringFromAsciiz(
|
||
OUT PUNICODE_STRING DestinationString,
|
||
IN PCSZ SourceString
|
||
)
|
||
{
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
RtlInitAnsiString( &AnsiString, SourceString );
|
||
Status = RtlAnsiStringToUnicodeString( DestinationString, &AnsiString, TRUE );
|
||
if (NT_SUCCESS( Status )) {
|
||
return( TRUE );
|
||
}
|
||
else {
|
||
return( FALSE );
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
RtlUpperString(
|
||
IN PSTRING DestinationString,
|
||
IN const STRING *SourceString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The RtlUpperString function copies the SourceString to the
|
||
DestinationString, converting it to upper case. 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 - Pointer to the source string.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSZ src, dst;
|
||
ULONG n;
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
dst = DestinationString->Buffer;
|
||
src = SourceString->Buffer;
|
||
n = SourceString->Length;
|
||
if ((USHORT)n > DestinationString->MaximumLength) {
|
||
n = DestinationString->MaximumLength;
|
||
}
|
||
DestinationString->Length = (USHORT)n;
|
||
while (n) {
|
||
*dst++ = RtlUpperChar(*src++);
|
||
n--;
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RtlAppendAsciizToString (
|
||
IN PSTRING Destination,
|
||
IN PCSZ Source OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine appends the supplied ASCIIZ string to an existing PSTRING.
|
||
|
||
It will copy bytes from the Source PSZ to the destination PSTRING up to
|
||
the destinations PSTRING->MaximumLength field.
|
||
|
||
Arguments:
|
||
|
||
IN PSTRING Destination, - Supplies a pointer to the destination string
|
||
IN PSZ 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;
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
if (ARGUMENT_PRESENT( Source )) {
|
||
n = (USHORT)strlen( Source );
|
||
|
||
if ((n + Destination->Length) > Destination->MaximumLength) {
|
||
return( STATUS_BUFFER_TOO_SMALL );
|
||
}
|
||
|
||
RtlMoveMemory( &Destination->Buffer[ Destination->Length ], Source, n );
|
||
Destination->Length += n;
|
||
}
|
||
|
||
return( STATUS_SUCCESS );
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
RtlAppendStringToString (
|
||
IN PSTRING Destination,
|
||
IN const 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;
|
||
|
||
RTL_PAGED_CODE();
|
||
|
||
if (n) {
|
||
if ((n + Destination->Length) > Destination->MaximumLength) {
|
||
return( STATUS_BUFFER_TOO_SMALL );
|
||
}
|
||
|
||
RtlMoveMemory( &Destination->Buffer[ Destination->Length ],
|
||
Source->Buffer,
|
||
n
|
||
);
|
||
Destination->Length += n;
|
||
}
|
||
|
||
return( STATUS_SUCCESS );
|
||
}
|
||
|
||
#if !defined(_X86_) && !defined(_AMD64_)
|
||
|
||
SIZE_T
|
||
NTAPI
|
||
RtlCompareMemoryUlong(
|
||
PVOID Source,
|
||
SIZE_T Length,
|
||
ULONG Pattern
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function compares two blocks of memory and returns the number
|
||
of bytes that compared equal.
|
||
|
||
N.B. This routine requires that the source address is aligned on a
|
||
longword boundary and that the length is an even multiple of
|
||
longwords.
|
||
|
||
Arguments:
|
||
|
||
Source - Supplies a pointer to the block of memory to compare against.
|
||
|
||
Length - Supplies the Length, in bytes, of the memory to be
|
||
compared.
|
||
|
||
Pattern - Supplies a 32-bit pattern to compare against the block of
|
||
memory.
|
||
|
||
Return Value:
|
||
|
||
The number of bytes that compared equal is returned as the function
|
||
value. If all bytes compared equal, then the length of the orginal
|
||
block of memory is returned. Returns zero if either the Source
|
||
address is not longword aligned or the length is not a multiple of
|
||
longwords.
|
||
|
||
--*/
|
||
{
|
||
SIZE_T CountLongs;
|
||
PULONG p = (PULONG)Source;
|
||
PCHAR p1, p2;
|
||
|
||
if (((ULONG_PTR)p & (sizeof( ULONG )-1)) ||
|
||
(Length & (sizeof( ULONG )-1))
|
||
) {
|
||
return( 0 );
|
||
}
|
||
|
||
CountLongs = Length / sizeof( ULONG );
|
||
while (CountLongs--) {
|
||
if (*p++ != Pattern) {
|
||
p1 = (PCHAR)(p - 1);
|
||
p2 = (PCHAR)&Pattern;
|
||
Length = p1 - (PCHAR)Source;
|
||
while (*p1++ == *p2++) {
|
||
if (p1 > (PCHAR)p) {
|
||
break;
|
||
}
|
||
|
||
Length++;
|
||
}
|
||
}
|
||
}
|
||
|
||
return( Length );
|
||
}
|
||
|
||
#endif // !defined(_X86_) && !defined(_AMD64_)
|