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.
875 lines
25 KiB
875 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 2001-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
CmnMisc.c
|
|
|
|
Abstract:
|
|
|
|
Miscellaneous common routines
|
|
|
|
Author:
|
|
|
|
George V. Reilly (GeorgeRe) 06-Dec-2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#if defined(ALLOC_PRAGMA) && defined(KERNEL_PRIV)
|
|
|
|
#pragma alloc_text( INIT, HttpCmnInitializeHttpCharsTable )
|
|
|
|
#endif // ALLOC_PRAGMA && KERNEL_PRIV
|
|
|
|
#if 0 // Non-Pageable Functions
|
|
NOT PAGEABLE -- strnchr
|
|
NOT PAGEABLE -- wcsnchr
|
|
NOT PAGEABLE -- HttpStringToULongLong
|
|
NOT PAGEABLE -- HttpStringToULong
|
|
NOT PAGEABLE -- HttpStringToUShort
|
|
NOT PAGEABLE -- HttpFillBufferTrap
|
|
NOT PAGEABLE -- HttpFillBuffer
|
|
NOT PAGEABLE -- HttpStatusToString
|
|
#endif // Non-Pageable Functions
|
|
|
|
|
|
DECLSPEC_ALIGN(UL_CACHE_LINE) ULONG HttpChars[256];
|
|
DECLSPEC_ALIGN(UL_CACHE_LINE) WCHAR FastPopChars[256];
|
|
DECLSPEC_ALIGN(UL_CACHE_LINE) WCHAR DummyPopChars[256];
|
|
DECLSPEC_ALIGN(UL_CACHE_LINE) WCHAR FastUpcaseChars[256];
|
|
DECLSPEC_ALIGN(UL_CACHE_LINE) WCHAR AnsiToUnicodeMap[256];
|
|
|
|
//
|
|
// Counted version of strchr()
|
|
//
|
|
|
|
char*
|
|
strnchr(
|
|
const char* string,
|
|
char c,
|
|
size_t count
|
|
)
|
|
{
|
|
const char* end = string + count;
|
|
const char* s;
|
|
|
|
for (s = string; s < end; ++s)
|
|
{
|
|
if (c == *s)
|
|
return (char*) s;
|
|
}
|
|
|
|
return NULL;
|
|
} // strnchr
|
|
|
|
|
|
//
|
|
// Counted version of wcschr()
|
|
//
|
|
wchar_t*
|
|
wcsnchr(
|
|
const wchar_t* string,
|
|
wint_t c,
|
|
size_t count
|
|
)
|
|
{
|
|
const wchar_t* end = string + count;
|
|
const wchar_t* s;
|
|
|
|
for (s = string; s < end; ++s)
|
|
{
|
|
if (c == *s)
|
|
return (wchar_t*) s;
|
|
}
|
|
|
|
return NULL;
|
|
} // wcsnchr
|
|
|
|
|
|
#define SET_HTTP_FLAGS(Set, Flags) \
|
|
HttppCmnInitHttpCharsBySet((PUCHAR) (Set), sizeof(Set) - 1, (Flags))
|
|
|
|
__inline
|
|
VOID
|
|
HttppCmnInitHttpCharsBySet(
|
|
PUCHAR Set,
|
|
ULONG SetSize,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
ASSERT(NULL != Set);
|
|
ASSERT(SetSize > 0);
|
|
ASSERT(0 != Flags);
|
|
ASSERT('\0' == Set[SetSize]);
|
|
|
|
for (i = 0; i < SetSize; ++i)
|
|
{
|
|
UCHAR Byte = Set[i];
|
|
ASSERT(0 == (HttpChars[Byte] & Flags));
|
|
|
|
HttpChars[Byte] |= Flags;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to initialize HttpChars[] and the other lookup tables.
|
|
See the declarations in HttpCmn.h
|
|
|
|
--*/
|
|
VOID
|
|
HttpCmnInitializeHttpCharsTable(
|
|
BOOLEAN EnableDBCS
|
|
)
|
|
{
|
|
ULONG i;
|
|
CHAR AnsiChar;
|
|
WCHAR WideChar;
|
|
NTSTATUS Status;
|
|
|
|
|
|
RtlZeroMemory(HttpChars, sizeof(HttpChars));
|
|
|
|
for (i = 0; i <= ASCII_MAX; ++i)
|
|
{
|
|
HttpChars[i] |= HTTP_CHAR;
|
|
}
|
|
|
|
SET_HTTP_FLAGS(HTTP_CTL_SET, HTTP_CTL);
|
|
|
|
SET_HTTP_FLAGS(HTTP_UPALPHA_SET, HTTP_UPCASE);
|
|
|
|
SET_HTTP_FLAGS(HTTP_LOALPHA_SET, HTTP_LOCASE);
|
|
|
|
SET_HTTP_FLAGS(HTTP_DIGITS_SET, HTTP_DIGIT);
|
|
|
|
SET_HTTP_FLAGS(HTTP_LWS_SET, HTTP_LWS);
|
|
|
|
SET_HTTP_FLAGS(HTTP_HEX_SET, HTTP_HEX);
|
|
|
|
SET_HTTP_FLAGS(HTTP_SEPARATORS_SET, HTTP_SEPARATOR);
|
|
|
|
SET_HTTP_FLAGS(HTTP_WS_TOKEN_SET, HTTP_WS_TOKEN);
|
|
|
|
SET_HTTP_FLAGS(HTTP_ISWHITE_SET, HTTP_ISWHITE);
|
|
|
|
for (i = 0; i <= ASCII_MAX; ++i)
|
|
{
|
|
if (!IS_HTTP_SEPARATOR(i) && !IS_HTTP_CTL(i))
|
|
{
|
|
HttpChars[i] |= HTTP_TOKEN;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i <= ANSI_HIGH_MAX; ++i)
|
|
{
|
|
if (!IS_HTTP_CTL(i) || IS_HTTP_LWS(i))
|
|
{
|
|
HttpChars[i] |= HTTP_PRINT;
|
|
}
|
|
|
|
if (!IS_HTTP_CTL(i) || IS_HTTP_WS_TOKEN(i))
|
|
{
|
|
HttpChars[i] |= HTTP_TEXT;
|
|
}
|
|
}
|
|
|
|
// Used in URI canonicalizer to identify '.', '/', '?' and '#'
|
|
HttpChars['.'] |= HTTP_CHAR_DOT;
|
|
HttpChars['/'] |= HTTP_CHAR_SLASH;
|
|
HttpChars['?'] |= HTTP_CHAR_QM_HASH;
|
|
HttpChars['#'] |= HTTP_CHAR_QM_HASH;
|
|
|
|
|
|
// URL flags initialization
|
|
|
|
//
|
|
// These US-ASCII characters are "excluded"; i.e., not URL_LEGAL (see RFC):
|
|
// '<' | '>' | ' ' (0x20)
|
|
// In addition, control characters (0x00-0x1F and 0x7F) and
|
|
// non US-ASCII characters (0x80-0xFF) are not URL_LEGAL.
|
|
//
|
|
SET_HTTP_FLAGS(URL_UNRESERVED_SET, URL_LEGAL);
|
|
SET_HTTP_FLAGS(URL_RESERVED_SET, URL_LEGAL);
|
|
// For compatibility with IIS 5.0 and DAV, we must allow
|
|
// the "unwise" characters in URLs.
|
|
SET_HTTP_FLAGS(URL_UNWISE_SET, URL_LEGAL);
|
|
SET_HTTP_FLAGS("%", URL_LEGAL);
|
|
|
|
SET_HTTP_FLAGS(URL_DIRTY_SET, URL_DIRTY);
|
|
// All characters outside US-ASCII range are considered dirty
|
|
for (i = ANSI_HIGH_MIN; i <= ANSI_HIGH_MAX; ++i)
|
|
HttpChars[i] |= URL_DIRTY;
|
|
|
|
SET_HTTP_FLAGS(URL_HOSTNAME_LABEL_LDH_SET, URL_HOSTNAME_LABEL);
|
|
|
|
SET_HTTP_FLAGS(URL_INVALID_SET, URL_INVALID);
|
|
|
|
SET_HTTP_FLAGS(URL_ILLEGAL_COMPUTERNAME_SET, URL_ILLEGAL_COMPUTERNAME);
|
|
|
|
//
|
|
// In DBCS locales we need to explicitly accept lead bytes that
|
|
// we would normally reject.
|
|
//
|
|
|
|
if (EnableDBCS)
|
|
{
|
|
// By definition, lead bytes are in the range 0x80-0xFF
|
|
for (i = ANSI_HIGH_MIN; i <= ANSI_HIGH_MAX; ++i)
|
|
{
|
|
#if KERNEL_PRIV
|
|
// These are copied from RTL NLS routines.
|
|
extern PUSHORT NlsLeadByteInfo;
|
|
BOOLEAN IsLeadByte
|
|
= (BOOLEAN) (((*(PUSHORT *) NlsLeadByteInfo)[i]) != 0);
|
|
#else // !KERNEL_PRIV
|
|
BOOLEAN IsLeadByte = (BOOLEAN) IsDBCSLeadByte((BYTE) i);
|
|
#endif // !KERNEL_PRIV
|
|
|
|
if (IsLeadByte)
|
|
{
|
|
HttpChars[i] |= HTTP_DBCS_LEAD_BYTE;
|
|
|
|
if (IS_HIGH_ANSI(i))
|
|
HttpChars[i] |= URL_LEGAL;
|
|
|
|
UlTrace(PARSER, (
|
|
"http!InitializeHttpUtil, "
|
|
"marking %x (%c) as a valid lead byte.\n",
|
|
i, i
|
|
));
|
|
}
|
|
else
|
|
{
|
|
// For the DBCS locales, almost all bytes above 128 are
|
|
// either lead bytes or valid single-byte characters.
|
|
|
|
AnsiChar = (CHAR) i;
|
|
|
|
Status = RtlMultiByteToUnicodeN(
|
|
&WideChar,
|
|
sizeof(WCHAR),
|
|
NULL,
|
|
(PCHAR) &AnsiChar,
|
|
1
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
HttpChars[i] |= URL_LEGAL;
|
|
|
|
UlTrace(PARSER, (
|
|
"http!InitializeHttpUtil, "
|
|
"marking %x (%c) as a legal DBCS character, %s.\n",
|
|
i, i,
|
|
HttpStatusToString(Status)
|
|
));
|
|
}
|
|
else
|
|
{
|
|
UlTrace(PARSER, (
|
|
"http!InitializeHttpUtil, "
|
|
"%x (%c) is not a legal DBCS character.\n",
|
|
i, i
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Build a lookup table that maps the 256 possible ANSI characters
|
|
// in the system code page to Unicode
|
|
|
|
for (i = 0; i <= ANSI_HIGH_MAX; ++i)
|
|
{
|
|
AnsiChar = (CHAR) i;
|
|
|
|
Status = RtlMultiByteToUnicodeN(
|
|
&WideChar,
|
|
sizeof(WCHAR),
|
|
NULL,
|
|
(PCHAR) &AnsiChar,
|
|
1
|
|
);
|
|
|
|
AnsiToUnicodeMap[i] = (NT_SUCCESS(Status) ? WideChar : 0);
|
|
|
|
// Also, handle upcasing the first 256 chars
|
|
FastUpcaseChars[i] = RtlUpcaseUnicodeChar((WCHAR) i);
|
|
}
|
|
|
|
//
|
|
// Fast path for PopChar. 0 => special handling.
|
|
//
|
|
|
|
RtlZeroMemory(FastPopChars, sizeof(FastPopChars));
|
|
RtlZeroMemory(DummyPopChars, sizeof(DummyPopChars));
|
|
|
|
for (i = 0; i <= ASCII_MAX; ++i)
|
|
{
|
|
UCHAR c = (UCHAR)i;
|
|
|
|
// (ALPHA | DIGIT | URL_LEGAL) && !IS_URL_DIRTY
|
|
if (IS_URL_TOKEN(c) && !IS_URL_DIRTY(c))
|
|
FastPopChars[i] = c;
|
|
}
|
|
|
|
// These characters are in the dirty set, so we need to set them explicitly
|
|
FastPopChars['.'] = L'.';
|
|
FastPopChars['/'] = L'/';
|
|
|
|
//
|
|
// Finally, initialize the UTF-8 data
|
|
//
|
|
|
|
HttpInitializeUtf8();
|
|
|
|
} // HttpCmnInitializeHttpCharsTable
|
|
|
|
|
|
|
|
#define MAX_ULONGLONG 18446744073709551615ui64
|
|
C_ASSERT(~0ui64 == MAX_ULONGLONG);
|
|
|
|
#define MAX_ULONG 0xFFFFFFFF
|
|
#define MAX_USHORT 0xFFFF
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Converts an ANSI or Unicode string to a ULONGLONG.
|
|
Fails on negative numbers, and assumes no preceding spaces.
|
|
|
|
Arguments:
|
|
|
|
IsUnicode Non-zero => pString is Unicode, otherwise it's ANSI.
|
|
pString The string to convert. Must point to the first digit.
|
|
StringLength Number of characters (ANSI or Unicode) in pString.
|
|
If zero, then the string must be NUL-terminated and
|
|
there may be non-digit characters before the
|
|
terminating NUL. Otherwise (counted string),
|
|
only digit characters may be present.
|
|
LeadingZerosAllowed String can/cannot start with leading zeros
|
|
Base The base of the string; must be 10 or 16
|
|
ppTerminator Pointer to the end of the numeric string. May be NULL.
|
|
pValue The return value of the converted ULONGLONG
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS Valid number
|
|
STATUS_INVALID_PARAMETER Bad digit
|
|
STATUS_SECTION_TOO_BIG Numeric overflow
|
|
|
|
*ppTerminator always points to the string terminator, if it wasn't NULL
|
|
on entry. *pValue is valid only for STATUS_SUCCESS.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
HttpStringToULongLong(
|
|
IN BOOLEAN IsUnicode,
|
|
IN PCVOID pString,
|
|
IN SIZE_T StringLength,
|
|
IN BOOLEAN LeadingZerosAllowed,
|
|
IN ULONG Base,
|
|
OUT PVOID* ppTerminator,
|
|
OUT PULONGLONG pValue
|
|
)
|
|
{
|
|
ULONGLONG Value = 0;
|
|
BOOLEAN ZeroTerminated = (BOOLEAN) (0 == StringLength);
|
|
BOOLEAN Decimal = (BOOLEAN) (10 == Base);
|
|
ULONG Mask = (Decimal ? HTTP_DIGIT : HTTP_HEX);
|
|
PCUCHAR pAnsiString = (PCUCHAR) pString;
|
|
PCWSTR pWideString = (PCWSTR) pString;
|
|
PVOID pLocalTerminator;
|
|
ULONGLONG OverflowLimit;
|
|
ULONG MaxLastDigit;
|
|
ULONG Index;
|
|
ULONG Char;
|
|
|
|
// If you've failed to call HttpCmnInitializeHttpCharsTable(),
|
|
// you'll hit this assertion
|
|
ASSERT(IS_HTTP_DIGIT('0'));
|
|
|
|
// If the caller doesn't care about the string terminator, just
|
|
// make ppTerminator point to something valid, so that we don't have
|
|
// to test it everywhere before assigning to it.
|
|
if (NULL == ppTerminator)
|
|
ppTerminator = &pLocalTerminator;
|
|
|
|
// Initialize ppTerminator to the beginning of the string
|
|
*ppTerminator = (PVOID) pString;
|
|
|
|
// Check for obviously invalid data
|
|
if (NULL == pString || NULL == pValue || (10 != Base && 16 != Base))
|
|
{
|
|
UlTraceError(PARSER, ("Invalid parameters\n"));
|
|
RETURN(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
// First character must be a valid digit
|
|
Char = (IsUnicode ? pWideString[0] : pAnsiString[0]);
|
|
|
|
if (!IS_ASCII(Char) || !IS_CHAR_TYPE(Char, Mask))
|
|
{
|
|
UlTraceError(PARSER, ("No digits\n"));
|
|
RETURN(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
// Check for leading zeros
|
|
if (!LeadingZerosAllowed && '0' == Char)
|
|
{
|
|
// If leading zeros are not allowed and the first character is zero,
|
|
// then it must be the only digit in the string.
|
|
|
|
if (ZeroTerminated)
|
|
{
|
|
// Check second digit
|
|
Char = (IsUnicode ? pWideString[1] : pAnsiString[1]);
|
|
|
|
if (IS_ASCII(Char) && IS_CHAR_TYPE(Char, Mask))
|
|
{
|
|
UlTraceError(PARSER, ("Second digit forbidden\n"));
|
|
RETURN(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// A counted string must have exactly one digit (the zero)
|
|
// in this case
|
|
if (StringLength != 1)
|
|
{
|
|
UlTraceError(PARSER, ("Second digit forbidden\n"));
|
|
RETURN(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
}
|
|
|
|
// The calculations are done this way in the hope that the compiler
|
|
// will use compile-time constants
|
|
if (Decimal)
|
|
{
|
|
OverflowLimit = (MAX_ULONGLONG / 10);
|
|
MaxLastDigit = MAX_ULONGLONG % 10;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(16 == Base);
|
|
OverflowLimit = (MAX_ULONGLONG >> 4);
|
|
MaxLastDigit = MAX_ULONGLONG & 0xF;
|
|
ASSERT(0xF == MaxLastDigit);
|
|
}
|
|
|
|
ASSERT(OverflowLimit < Base * OverflowLimit);
|
|
ASSERT(Base * OverflowLimit + MaxLastDigit == MAX_ULONGLONG);
|
|
|
|
// Loop through the string
|
|
|
|
for (Index = 0; ZeroTerminated || Index < StringLength; ++Index)
|
|
{
|
|
ULONGLONG NewValue;
|
|
ULONG Digit;
|
|
|
|
// Update ppTerminator first, in case of error
|
|
|
|
if (IsUnicode)
|
|
{
|
|
*ppTerminator = (PVOID) &pWideString[Index];
|
|
Char = pWideString[Index];
|
|
}
|
|
else
|
|
{
|
|
*ppTerminator = (PVOID) &pAnsiString[Index];
|
|
Char = pAnsiString[Index];
|
|
}
|
|
|
|
// Is Char is a valid digit?
|
|
|
|
if (!IS_ASCII(Char) || ! IS_CHAR_TYPE(Char, Mask))
|
|
{
|
|
if (ZeroTerminated)
|
|
{
|
|
// If the string is ultimately zero-terminated, but there
|
|
// are some non-digit characters after the number, that is
|
|
// not an error. Note: '\0' will fail the IS_CHAR_TYPE test.
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// For counted strings, only digits may be present
|
|
UlTraceError(PARSER, ("Invalid digit\n"));
|
|
RETURN(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
if (IS_HTTP_ALPHA(Char))
|
|
{
|
|
ASSERT(('A' <= Char && Char <= 'F')
|
|
|| ('a' <= Char && Char <= 'f'));
|
|
|
|
if (Decimal)
|
|
{
|
|
// Chars in the range [A-Fa-f] are invalid in decimal numbers
|
|
|
|
if (ZeroTerminated)
|
|
{
|
|
// Anything outside the range [0-9] terminates the loop
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// For counted decimal strings, only decimal digits
|
|
// may be present
|
|
UlTraceError(PARSER, ("Non-decimal digit\n"));
|
|
RETURN(STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
Digit = 0xA + (UPCASE_CHAR(Char) - 'A');
|
|
|
|
ASSERT(0xA <= Digit && Digit <= 0xF);
|
|
}
|
|
else
|
|
{
|
|
ASSERT('0' <= Char && Char <= '9');
|
|
Digit = Char - '0';
|
|
}
|
|
|
|
ASSERT(Digit < Base);
|
|
|
|
//
|
|
// Guard against arithmetic overflow. We just got a valid digit,
|
|
// but Value will (likely) overflow if we shift in another digit
|
|
//
|
|
|
|
if (Value >= OverflowLimit)
|
|
{
|
|
// Definite overflow
|
|
if (Value > OverflowLimit)
|
|
{
|
|
UlTraceError(PARSER, ("Numeric overflow\n"));
|
|
RETURN(STATUS_SECTION_TOO_BIG);
|
|
}
|
|
|
|
ASSERT(Value == OverflowLimit);
|
|
|
|
// May be able to accommodate the last digit
|
|
if (Digit > MaxLastDigit)
|
|
{
|
|
UlTraceError(PARSER, ("Numeric overflow\n"));
|
|
RETURN(STATUS_SECTION_TOO_BIG);
|
|
}
|
|
}
|
|
|
|
ASSERT(Value * Base <= MAX_ULONGLONG - Digit);
|
|
ASSERT(Value < Value * Base || 0 == Value);
|
|
|
|
if (Decimal)
|
|
NewValue = (10 * Value) + Digit;
|
|
else
|
|
NewValue = (Value << 4) | Digit;
|
|
|
|
ASSERT(NewValue > Value
|
|
|| (0 == Value && 0 == Digit
|
|
&& (LeadingZerosAllowed || (0 == Index))));
|
|
|
|
Value = NewValue;
|
|
}
|
|
|
|
// Must be a valid number if reached here
|
|
ASSERT(ZeroTerminated ? Index > 0 : Index == StringLength);
|
|
|
|
// Make ppTerminator point to the end of the string
|
|
if (IsUnicode)
|
|
*ppTerminator = (PVOID) &pWideString[Index];
|
|
else
|
|
*ppTerminator = (PVOID) &pAnsiString[Index];
|
|
|
|
*pValue = Value;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // HttpStringToULongLong
|
|
|
|
|
|
|
|
NTSTATUS
|
|
HttpStringToULong(
|
|
IN BOOLEAN IsUnicode,
|
|
IN PCVOID pString,
|
|
IN SIZE_T StringLength,
|
|
IN BOOLEAN LeadingZerosAllowed,
|
|
IN ULONG Base,
|
|
OUT PVOID* ppTerminator,
|
|
OUT PULONG pValue
|
|
)
|
|
{
|
|
ULONGLONG Value;
|
|
NTSTATUS Status;
|
|
|
|
Status = HttpStringToULongLong(
|
|
IsUnicode,
|
|
pString,
|
|
StringLength,
|
|
LeadingZerosAllowed,
|
|
Base,
|
|
ppTerminator,
|
|
&Value
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (Value > MAX_ULONG)
|
|
{
|
|
UlTraceError(PARSER, ("Numeric overflow\n"));
|
|
RETURN(STATUS_SECTION_TOO_BIG);
|
|
}
|
|
else
|
|
{
|
|
*pValue = (ULONG) Value;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // HttpStringToULong
|
|
|
|
|
|
|
|
NTSTATUS
|
|
HttpStringToUShort(
|
|
IN BOOLEAN IsUnicode,
|
|
IN PCVOID pString,
|
|
IN SIZE_T StringLength,
|
|
IN BOOLEAN LeadingZerosAllowed,
|
|
IN ULONG Base,
|
|
OUT PVOID* ppTerminator,
|
|
OUT PUSHORT pValue
|
|
)
|
|
{
|
|
ULONGLONG Value;
|
|
NTSTATUS Status;
|
|
|
|
Status = HttpStringToULongLong(
|
|
IsUnicode,
|
|
pString,
|
|
StringLength,
|
|
LeadingZerosAllowed,
|
|
Base,
|
|
ppTerminator,
|
|
&Value
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (Value > MAX_USHORT)
|
|
{
|
|
UlTraceError(PARSER, ("Numeric overflow\n"));
|
|
RETURN(STATUS_SECTION_TOO_BIG);
|
|
}
|
|
else
|
|
{
|
|
*pValue = (USHORT) Value;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // HttpStringToUShort
|
|
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
HttpFillBufferTrap(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(! "HttpFillBufferTrap");
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Fill an output buffer with a known pattern. Helps detect buffer overruns.
|
|
//
|
|
|
|
VOID
|
|
HttpFillBuffer(
|
|
PUCHAR pBuffer,
|
|
SIZE_T BufferLength
|
|
)
|
|
{
|
|
union
|
|
{
|
|
ULONG_PTR UlongPtr;
|
|
UCHAR Bytes[sizeof(ULONG_PTR)];
|
|
} FillPattern;
|
|
|
|
const ULONG_PTR Mask = sizeof(ULONG_PTR) - 1;
|
|
|
|
ULONG_PTR i;
|
|
ULONG_PTR OriginalBufferLength = BufferLength;
|
|
PUCHAR pOriginalBuffer = pBuffer;
|
|
PULONG_PTR pAlignedBuffer;
|
|
|
|
ASSERT(NULL != pBuffer);
|
|
ASSERT(BufferLength > 0);
|
|
|
|
FillPattern.UlongPtr = (ULONG_PTR) &HttpFillBufferTrap;
|
|
|
|
// Fill any unaligned bytes at the beginning of the buffer
|
|
|
|
for (i = (ULONG_PTR) pBuffer;
|
|
(i & Mask) != 0 && BufferLength > 0;
|
|
++i, --BufferLength
|
|
)
|
|
{
|
|
*pBuffer++ = FillPattern.Bytes[i & Mask];
|
|
}
|
|
|
|
ASSERT(((ULONG_PTR) pBuffer & Mask) == 0);
|
|
|
|
// Fill as much as possible of the buffer with ULONG_PTRs
|
|
|
|
pAlignedBuffer = (PULONG_PTR) pBuffer;
|
|
|
|
for (i = (BufferLength & ~Mask); i > 0; i -= sizeof(ULONG_PTR))
|
|
{
|
|
ASSERT((i & Mask) == 0);
|
|
*pAlignedBuffer++ = FillPattern.UlongPtr;
|
|
}
|
|
|
|
// Fill any unaligned bytes at the tail of the buffer
|
|
pBuffer = (PUCHAR) pAlignedBuffer;
|
|
ASSERT(((ULONG_PTR) pBuffer & Mask) == 0);
|
|
|
|
for (i = 0; i != (BufferLength & Mask); ++i)
|
|
{
|
|
*pBuffer++ = FillPattern.Bytes[i & Mask];
|
|
}
|
|
|
|
ASSERT(pOriginalBuffer + OriginalBufferLength == pBuffer);
|
|
|
|
} // HttpFillBuffer
|
|
|
|
#endif // DBG
|
|
|
|
|
|
//
|
|
// Convert an NTSTATUS to a string, for use in debug spew.
|
|
//
|
|
|
|
PCSTR
|
|
HttpStatusToString(
|
|
NTSTATUS Status
|
|
)
|
|
{
|
|
static NTSTATUS s_KnownUnhandledStatus = 0;
|
|
PCSTR String;
|
|
|
|
switch (Status)
|
|
{
|
|
default:
|
|
// If you hit this, add the newly used status code below
|
|
WriteGlobalStringLog("Unhandled NTSTATUS, 0x%08lX\n", Status);
|
|
|
|
// Only assert once. If you've got two new NTSTATUSes, well, tough.
|
|
if (Status != s_KnownUnhandledStatus)
|
|
{
|
|
ASSERT(! "Unhandled NTSTATUS");
|
|
s_KnownUnhandledStatus = Status;
|
|
}
|
|
|
|
String = "<STATUS_???>";
|
|
break;
|
|
|
|
#define STATUS_CASE(n, s) \
|
|
case s: \
|
|
{ \
|
|
C_ASSERT((NTSTATUS) n == s);\
|
|
String = #s; \
|
|
break; \
|
|
}
|
|
|
|
STATUS_CASE( 0xC0000022, STATUS_ACCESS_DENIED );
|
|
STATUS_CASE( 0xC0000005, STATUS_ACCESS_VIOLATION );
|
|
STATUS_CASE( 0xC000020A, STATUS_ADDRESS_ALREADY_EXISTS );
|
|
STATUS_CASE( 0xC0000099, STATUS_ALLOTTED_SPACE_EXCEEDED );
|
|
STATUS_CASE( 0x80000005, STATUS_BUFFER_OVERFLOW );
|
|
STATUS_CASE( 0xC0000023, STATUS_BUFFER_TOO_SMALL );
|
|
STATUS_CASE( 0xC0000120, STATUS_CANCELLED );
|
|
STATUS_CASE( 0xC0000018, STATUS_CONFLICTING_ADDRESSES );
|
|
STATUS_CASE( 0xC0000241, STATUS_CONNECTION_ABORTED );
|
|
STATUS_CASE( 0xC000023B, STATUS_CONNECTION_ACTIVE );
|
|
STATUS_CASE( 0xC000020C, STATUS_CONNECTION_DISCONNECTED );
|
|
STATUS_CASE( 0xC000023A, STATUS_CONNECTION_INVALID );
|
|
STATUS_CASE( 0xC0000236, STATUS_CONNECTION_REFUSED );
|
|
STATUS_CASE( 0xC000020D, STATUS_CONNECTION_RESET );
|
|
STATUS_CASE( 0xC00002C5, STATUS_DATATYPE_MISALIGNMENT_ERROR );
|
|
STATUS_CASE( 0xC000021B, STATUS_DATA_NOT_ACCEPTED );
|
|
STATUS_CASE( 0xC000003C, STATUS_DATA_OVERRUN );
|
|
STATUS_CASE( 0xC000007F, STATUS_DISK_FULL );
|
|
STATUS_CASE( 0xC00000BD, STATUS_DUPLICATE_NAME );
|
|
STATUS_CASE( 0xC0000011, STATUS_END_OF_FILE );
|
|
STATUS_CASE( 0xC0000098, STATUS_FILE_INVALID );
|
|
STATUS_CASE( 0xC0000004, STATUS_INFO_LENGTH_MISMATCH );
|
|
STATUS_CASE( 0xC000009A, STATUS_INSUFFICIENT_RESOURCES );
|
|
STATUS_CASE( 0xC0000095, STATUS_INTEGER_OVERFLOW );
|
|
STATUS_CASE( 0xC0000141, STATUS_INVALID_ADDRESS );
|
|
STATUS_CASE( 0xC0000010, STATUS_INVALID_DEVICE_REQUEST );
|
|
STATUS_CASE( 0xC0000184, STATUS_INVALID_DEVICE_STATE );
|
|
STATUS_CASE( 0xC0000008, STATUS_INVALID_HANDLE );
|
|
STATUS_CASE( 0xC0000084, STATUS_INVALID_ID_AUTHORITY );
|
|
STATUS_CASE( 0xC00000C3, STATUS_INVALID_NETWORK_RESPONSE );
|
|
STATUS_CASE( 0xC000005A, STATUS_INVALID_OWNER );
|
|
STATUS_CASE( 0xC000000D, STATUS_INVALID_PARAMETER );
|
|
STATUS_CASE( 0xC00000B5, STATUS_IO_TIMEOUT );
|
|
STATUS_CASE( 0xC0000016, STATUS_MORE_PROCESSING_REQUIRED );
|
|
STATUS_CASE( 0xC0000106, STATUS_NAME_TOO_LONG );
|
|
STATUS_CASE( 0xC0000225, STATUS_NOT_FOUND );
|
|
STATUS_CASE( 0xC0000002, STATUS_NOT_IMPLEMENTED );
|
|
STATUS_CASE( 0xC00000BB, STATUS_NOT_SUPPORTED );
|
|
STATUS_CASE( 0xC00002F1, STATUS_NO_IP_ADDRESSES );
|
|
STATUS_CASE( 0xC0000017, STATUS_NO_MEMORY );
|
|
STATUS_CASE( 0x8000001A, STATUS_NO_MORE_ENTRIES );
|
|
STATUS_CASE( 0x80000006, STATUS_NO_MORE_FILES );
|
|
STATUS_CASE( 0xC000000F, STATUS_NO_SUCH_FILE );
|
|
STATUS_CASE( 0xC000029F, STATUS_NO_TRACKING_SERVICE );
|
|
STATUS_CASE( 0xC000022B, STATUS_OBJECTID_EXISTS );
|
|
STATUS_CASE( 0xC0000035, STATUS_OBJECT_NAME_COLLISION );
|
|
STATUS_CASE( 0xC0000033, STATUS_OBJECT_NAME_INVALID );
|
|
STATUS_CASE( 0xC0000034, STATUS_OBJECT_NAME_NOT_FOUND );
|
|
STATUS_CASE( 0xC0000039, STATUS_OBJECT_PATH_INVALID );
|
|
STATUS_CASE( 0xC000003A, STATUS_OBJECT_PATH_NOT_FOUND );
|
|
STATUS_CASE( 0xC000003B, STATUS_OBJECT_PATH_SYNTAX_BAD );
|
|
STATUS_CASE( 0x00000103, STATUS_PENDING );
|
|
STATUS_CASE( 0xC00000D9, STATUS_PIPE_EMPTY );
|
|
STATUS_CASE( 0xC0000037, STATUS_PORT_DISCONNECTED );
|
|
STATUS_CASE( 0xC000022D, STATUS_RETRY );
|
|
STATUS_CASE( 0xC0000059, STATUS_REVISION_MISMATCH );
|
|
STATUS_CASE( 0xC0000040, STATUS_SECTION_TOO_BIG );
|
|
STATUS_CASE( 0xC0000043, STATUS_SHARING_VIOLATION );
|
|
STATUS_CASE( 0x00000000, STATUS_SUCCESS );
|
|
STATUS_CASE( 0xC0000001, STATUS_UNSUCCESSFUL );
|
|
STATUS_CASE( 0xC0000295, STATUS_WMI_GUID_NOT_FOUND );
|
|
}
|
|
|
|
return String;
|
|
|
|
} // HttpStatusToString
|