#ifndef _PH_PHBASESUP_H #define _PH_PHBASESUP_H #ifdef __cplusplus extern "C" { #endif BOOLEAN PhBaseInitialization( VOID ); // Threads #ifdef DEBUG struct _PH_AUTO_POOL; typedef struct _PH_AUTO_POOL *PPH_AUTO_POOL; typedef struct _PHP_BASE_THREAD_DBG { CLIENT_ID ClientId; LIST_ENTRY ListEntry; PVOID StartAddress; PVOID Parameter; PPH_AUTO_POOL CurrentAutoPool; } PHP_BASE_THREAD_DBG, *PPHP_BASE_THREAD_DBG; extern ULONG PhDbgThreadDbgTlsIndex; extern LIST_ENTRY PhDbgThreadListHead; extern PH_QUEUED_LOCK PhDbgThreadListLock; #endif PHLIBAPI HANDLE NTAPI PhCreateThread( _In_opt_ SIZE_T StackSize, _In_ PUSER_THREAD_START_ROUTINE StartAddress, _In_opt_ PVOID Parameter ); // DLLs FORCEINLINE PVOID PhGetDllHandle( _In_ PWSTR DllName ) { UNICODE_STRING dllName; PVOID dllHandle; RtlInitUnicodeString(&dllName, DllName); if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &dllName, &dllHandle))) return dllHandle; else return NULL; } FORCEINLINE PVOID PhGetProcedureAddress( _In_ PVOID DllHandle, _In_opt_ PSTR ProcedureName, _In_opt_ ULONG ProcedureNumber ) { NTSTATUS status; ANSI_STRING procedureName; PVOID procedureAddress; if (ProcedureName) { RtlInitAnsiString(&procedureName, ProcedureName); status = LdrGetProcedureAddress( DllHandle, &procedureName, 0, &procedureAddress ); } else { status = LdrGetProcedureAddress( DllHandle, NULL, ProcedureNumber, &procedureAddress ); } if (!NT_SUCCESS(status)) return NULL; return procedureAddress; } // Misc. system PHLIBAPI VOID NTAPI PhQuerySystemTime( _Out_ PLARGE_INTEGER SystemTime ); PHLIBAPI VOID NTAPI PhQueryTimeZoneBias( _Out_ PLARGE_INTEGER TimeZoneBias ); PHLIBAPI VOID NTAPI PhSystemTimeToLocalTime( _In_ PLARGE_INTEGER SystemTime, _Out_ PLARGE_INTEGER LocalTime ); PHLIBAPI VOID NTAPI PhLocalTimeToSystemTime( _In_ PLARGE_INTEGER LocalTime, _Out_ PLARGE_INTEGER SystemTime ); // Heap _May_raise_ _Check_return_ _Ret_notnull_ _Post_writable_byte_size_(Size) PHLIBAPI PVOID NTAPI PhAllocate( _In_ SIZE_T Size ); PHLIBAPI PVOID NTAPI PhAllocateSafe( _In_ SIZE_T Size ); PHLIBAPI PVOID NTAPI PhAllocateExSafe( _In_ SIZE_T Size, _In_ ULONG Flags ); PHLIBAPI VOID NTAPI PhFree( _Frees_ptr_opt_ PVOID Memory ); _May_raise_ _Post_writable_byte_size_(Size) PHLIBAPI PVOID NTAPI PhReAllocate( _Frees_ptr_ PVOID Memory, _In_ SIZE_T Size ); PHLIBAPI PVOID NTAPI PhReAllocateSafe( _In_ PVOID Memory, _In_ SIZE_T Size ); _Check_return_ _Ret_maybenull_ PHLIBAPI PVOID NTAPI PhAllocatePage( _In_ SIZE_T Size, _Out_opt_ PSIZE_T NewSize ); PHLIBAPI VOID NTAPI PhFreePage( _Frees_ptr_opt_ PVOID Memory ); FORCEINLINE PVOID PhAllocateCopy( _In_ PVOID Data, _In_ SIZE_T Size ) { PVOID copy; copy = PhAllocate(Size); memcpy(copy, Data, Size); return copy; } // Event #define PH_EVENT_SET 0x1 #define PH_EVENT_SET_SHIFT 0 #define PH_EVENT_REFCOUNT_SHIFT 1 #define PH_EVENT_REFCOUNT_INC 0x2 #define PH_EVENT_REFCOUNT_MASK (((ULONG_PTR)1 << 15) - 1) /** * A fast event object. * * \remarks This event object does not use a kernel event object until necessary, and frees the * object automatically when it is no longer needed. */ typedef struct _PH_EVENT { union { ULONG_PTR Value; struct { USHORT Set : 1; USHORT RefCount : 15; UCHAR Reserved; UCHAR AvailableForUse; #ifdef _WIN64 ULONG Spare; #endif }; }; HANDLE EventHandle; } PH_EVENT, *PPH_EVENT; C_ASSERT(sizeof(PH_EVENT) == sizeof(ULONG_PTR) + sizeof(HANDLE)); #define PH_EVENT_INIT { { PH_EVENT_REFCOUNT_INC }, NULL } PHLIBAPI VOID FASTCALL PhfInitializeEvent( _Out_ PPH_EVENT Event ); #define PhSetEvent PhfSetEvent PHLIBAPI VOID FASTCALL PhfSetEvent( _Inout_ PPH_EVENT Event ); PHLIBAPI BOOLEAN FASTCALL PhfWaitForEvent( _Inout_ PPH_EVENT Event, _In_opt_ PLARGE_INTEGER Timeout ); FORCEINLINE BOOLEAN PhWaitForEvent( _Inout_ PPH_EVENT Event, _In_opt_ PLARGE_INTEGER Timeout ) { if (Event->Set) return TRUE; return PhfWaitForEvent(Event, Timeout); } #define PhResetEvent PhfResetEvent PHLIBAPI VOID FASTCALL PhfResetEvent( _Inout_ PPH_EVENT Event ); FORCEINLINE VOID PhInitializeEvent( _Out_ PPH_EVENT Event ) { Event->Value = PH_EVENT_REFCOUNT_INC; Event->EventHandle = NULL; } /** * Determines whether an event object is set. * * \param Event A pointer to an event object. * * \return TRUE if the event object is set, otherwise FALSE. */ FORCEINLINE BOOLEAN PhTestEvent( _In_ PPH_EVENT Event ) { return (BOOLEAN)Event->Set; } // Barrier #define PH_BARRIER_COUNT_SHIFT 0 #define PH_BARRIER_COUNT_MASK (((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 / 2 - 1)) - 1) #define PH_BARRIER_COUNT_INC ((LONG_PTR)1 << PH_BARRIER_COUNT_SHIFT) #define PH_BARRIER_TARGET_SHIFT (sizeof(ULONG_PTR) * 8 / 2) #define PH_BARRIER_TARGET_MASK (((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 / 2 - 1)) - 1) #define PH_BARRIER_TARGET_INC ((LONG_PTR)1 << PH_BARRIER_TARGET_SHIFT) #define PH_BARRIER_WAKING ((LONG_PTR)1 << (sizeof(ULONG_PTR) * 8 - 1)) #define PH_BARRIER_MASTER 1 #define PH_BARRIER_SLAVE 2 #define PH_BARRIER_OBSERVER 3 typedef struct _PH_BARRIER { ULONG_PTR Value; PH_WAKE_EVENT WakeEvent; } PH_BARRIER, *PPH_BARRIER; #define PH_BARRIER_INIT(Target) { (ULONG_PTR)(Target) << PH_BARRIER_TARGET_SHIFT, PH_WAKE_EVENT_INIT } PHLIBAPI VOID FASTCALL PhfInitializeBarrier( _Out_ PPH_BARRIER Barrier, _In_ ULONG_PTR Target ); #define PhWaitForBarrier PhfWaitForBarrier PHLIBAPI BOOLEAN FASTCALL PhfWaitForBarrier( _Inout_ PPH_BARRIER Barrier, _In_ BOOLEAN Spin ); FORCEINLINE VOID PhInitializeBarrier( _Out_ PPH_BARRIER Barrier, _In_ ULONG_PTR Target ) { Barrier->Value = Target << PH_BARRIER_TARGET_SHIFT; PhInitializeQueuedLock(&Barrier->WakeEvent); } // Rundown protection #define PH_RUNDOWN_ACTIVE 0x1 #define PH_RUNDOWN_REF_SHIFT 1 #define PH_RUNDOWN_REF_INC 0x2 typedef struct _PH_RUNDOWN_PROTECT { ULONG_PTR Value; } PH_RUNDOWN_PROTECT, *PPH_RUNDOWN_PROTECT; #define PH_RUNDOWN_PROTECT_INIT { 0 } typedef struct _PH_RUNDOWN_WAIT_BLOCK { ULONG_PTR Count; PH_EVENT WakeEvent; } PH_RUNDOWN_WAIT_BLOCK, *PPH_RUNDOWN_WAIT_BLOCK; PHLIBAPI VOID FASTCALL PhfInitializeRundownProtection( _Out_ PPH_RUNDOWN_PROTECT Protection ); PHLIBAPI BOOLEAN FASTCALL PhfAcquireRundownProtection( _Inout_ PPH_RUNDOWN_PROTECT Protection ); PHLIBAPI VOID FASTCALL PhfReleaseRundownProtection( _Inout_ PPH_RUNDOWN_PROTECT Protection ); PHLIBAPI VOID FASTCALL PhfWaitForRundownProtection( _Inout_ PPH_RUNDOWN_PROTECT Protection ); FORCEINLINE VOID PhInitializeRundownProtection( _Out_ PPH_RUNDOWN_PROTECT Protection ) { Protection->Value = 0; } FORCEINLINE BOOLEAN PhAcquireRundownProtection( _Inout_ PPH_RUNDOWN_PROTECT Protection ) { ULONG_PTR value; value = Protection->Value & ~PH_RUNDOWN_ACTIVE; // fail fast path when rundown is active if ((ULONG_PTR)_InterlockedCompareExchangePointer( (PVOID *)&Protection->Value, (PVOID)(value + PH_RUNDOWN_REF_INC), (PVOID)value ) == value) { return TRUE; } else { return PhfAcquireRundownProtection(Protection); } } FORCEINLINE VOID PhReleaseRundownProtection( _Inout_ PPH_RUNDOWN_PROTECT Protection ) { ULONG_PTR value; value = Protection->Value & ~PH_RUNDOWN_ACTIVE; // Fail fast path when rundown is active if ((ULONG_PTR)_InterlockedCompareExchangePointer( (PVOID *)&Protection->Value, (PVOID)(value - PH_RUNDOWN_REF_INC), (PVOID)value ) != value) { PhfReleaseRundownProtection(Protection); } } FORCEINLINE VOID PhWaitForRundownProtection( _Inout_ PPH_RUNDOWN_PROTECT Protection ) { ULONG_PTR value; value = (ULONG_PTR)_InterlockedCompareExchangePointer( (PVOID *)&Protection->Value, (PVOID)PH_RUNDOWN_ACTIVE, (PVOID)0 ); if (value != 0 && value != PH_RUNDOWN_ACTIVE) PhfWaitForRundownProtection(Protection); } // One-time initialization #define PH_INITONCE_SHIFT 31 #define PH_INITONCE_INITIALIZING (0x1 << PH_INITONCE_SHIFT) #define PH_INITONCE_INITIALIZING_SHIFT PH_INITONCE_SHIFT typedef struct _PH_INITONCE { PH_EVENT Event; } PH_INITONCE, *PPH_INITONCE; C_ASSERT(PH_INITONCE_SHIFT >= FIELD_OFFSET(PH_EVENT, AvailableForUse) * 8); #define PH_INITONCE_INIT { PH_EVENT_INIT } #define PhInitializeInitOnce PhfInitializeInitOnce PHLIBAPI VOID FASTCALL PhfInitializeInitOnce( _Out_ PPH_INITONCE InitOnce ); PHLIBAPI BOOLEAN FASTCALL PhfBeginInitOnce( _Inout_ PPH_INITONCE InitOnce ); #define PhEndInitOnce PhfEndInitOnce PHLIBAPI VOID FASTCALL PhfEndInitOnce( _Inout_ PPH_INITONCE InitOnce ); FORCEINLINE BOOLEAN PhBeginInitOnce( _Inout_ PPH_INITONCE InitOnce ) { if (InitOnce->Event.Set) return FALSE; else return PhfBeginInitOnce(InitOnce); } FORCEINLINE BOOLEAN PhTestInitOnce( _In_ PPH_INITONCE InitOnce ) { return (BOOLEAN)InitOnce->Event.Set; } // String PHLIBAPI SIZE_T NTAPI PhCountStringZ( _In_ PWSTR String ); PHLIBAPI PSTR NTAPI PhDuplicateBytesZ( _In_ PSTR String ); PHLIBAPI PSTR NTAPI PhDuplicateBytesZSafe( _In_ PSTR String ); PHLIBAPI PWSTR NTAPI PhDuplicateStringZ( _In_ PWSTR String ); PHLIBAPI BOOLEAN NTAPI PhCopyBytesZ( _In_ PSTR InputBuffer, _In_ SIZE_T InputCount, _Out_writes_opt_z_(OutputCount) PSTR OutputBuffer, _In_ SIZE_T OutputCount, _Out_opt_ PSIZE_T ReturnCount ); PHLIBAPI BOOLEAN NTAPI PhCopyStringZ( _In_ PWSTR InputBuffer, _In_ SIZE_T InputCount, _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, _In_ SIZE_T OutputCount, _Out_opt_ PSIZE_T ReturnCount ); PHLIBAPI BOOLEAN NTAPI PhCopyStringZFromBytes( _In_ PSTR InputBuffer, _In_ SIZE_T InputCount, _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, _In_ SIZE_T OutputCount, _Out_opt_ PSIZE_T ReturnCount ); PHLIBAPI BOOLEAN NTAPI PhCopyStringZFromMultiByte( _In_ PSTR InputBuffer, _In_ SIZE_T InputCount, _Out_writes_opt_z_(OutputCount) PWSTR OutputBuffer, _In_ SIZE_T OutputCount, _Out_opt_ PSIZE_T ReturnCount ); PHLIBAPI LONG NTAPI PhCompareStringZNatural( _In_ PWSTR A, _In_ PWSTR B, _In_ BOOLEAN IgnoreCase ); FORCEINLINE BOOLEAN PhAreCharactersDifferent( _In_ WCHAR Char1, _In_ WCHAR Char2 ) { WCHAR d; d = Char1 ^ Char2; // We ignore bits beyond bit 5 because bit 6 is the case bit, and also we // don't support localization here. if (d & 0x1f) return TRUE; return FALSE; } FORCEINLINE BOOLEAN PhIsDigitCharacter( _In_ WCHAR Char ) { return (USHORT)(Char - '0') < 10; } FORCEINLINE LONG PhCompareBytesZ( _In_ PSTR String1, _In_ PSTR String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) return strcmp(String1, String2); else return _stricmp(String1, String2); } FORCEINLINE BOOLEAN PhEqualBytesZ( _In_ PSTR String1, _In_ PSTR String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) return strcmp(String1, String2) == 0; else return _stricmp(String1, String2) == 0; } FORCEINLINE LONG PhCompareStringZ( _In_ PWSTR String1, _In_ PWSTR String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) return wcscmp(String1, String2); else return _wcsicmp(String1, String2); } FORCEINLINE BOOLEAN PhEqualStringZ( _In_ PWSTR String1, _In_ PWSTR String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) { return wcscmp(String1, String2) == 0; } else { // wcsicmp is very expensive, so we do a quick check for negatives first. if (PhAreCharactersDifferent(String1[0], String2[0])) return FALSE; return _wcsicmp(String1, String2) == 0; } } typedef struct _PH_STRINGREF { /** The length, in bytes, of the string. */ SIZE_T Length; /** The buffer containing the contents of the string. */ PWCH Buffer; } PH_STRINGREF, *PPH_STRINGREF; typedef struct _PH_BYTESREF { /** The length, in bytes, of the string. */ SIZE_T Length; /** The buffer containing the contents of the string. */ PCH Buffer; } PH_BYTESREF, *PPH_BYTESREF; typedef struct _PH_RELATIVE_BYTESREF { /** The length, in bytes, of the string. */ ULONG Length; /** A user-defined offset. */ ULONG Offset; } PH_RELATIVE_BYTESREF, *PPH_RELATIVE_BYTESREF, PH_RELATIVE_STRINGREF, *PPH_RELATIVE_STRINGREF; #define PH_STRINGREF_INIT(String) { sizeof(String) - sizeof(WCHAR), (String) } #define PH_BYTESREF_INIT(String) { sizeof(String) - sizeof(CHAR), (String) } FORCEINLINE VOID PhInitializeStringRef( _Out_ PPH_STRINGREF String, _In_ PWSTR Buffer ) { String->Length = wcslen(Buffer) * sizeof(WCHAR); String->Buffer = Buffer; } FORCEINLINE VOID PhInitializeStringRefLongHint( _Out_ PPH_STRINGREF String, _In_ PWSTR Buffer ) { String->Length = PhCountStringZ(Buffer) * sizeof(WCHAR); String->Buffer = Buffer; } FORCEINLINE VOID PhInitializeBytesRef( _Out_ PPH_BYTESREF Bytes, _In_ PSTR Buffer ) { Bytes->Length = strlen(Buffer) * sizeof(CHAR); Bytes->Buffer = Buffer; } FORCEINLINE VOID PhInitializeEmptyStringRef( _Out_ PPH_STRINGREF String ) { String->Length = 0; String->Buffer = NULL; } FORCEINLINE BOOLEAN PhStringRefToUnicodeString( _In_ PPH_STRINGREF String, _Out_ PUNICODE_STRING UnicodeString ) { UnicodeString->Length = (USHORT)String->Length; UnicodeString->MaximumLength = (USHORT)String->Length; UnicodeString->Buffer = String->Buffer; return String->Length <= UNICODE_STRING_MAX_BYTES; } FORCEINLINE VOID PhUnicodeStringToStringRef( _In_ PUNICODE_STRING UnicodeString, _Out_ PPH_STRINGREF String ) { String->Length = UnicodeString->Length; String->Buffer = UnicodeString->Buffer; } PHLIBAPI LONG NTAPI PhCompareStringRef( _In_ PPH_STRINGREF String1, _In_ PPH_STRINGREF String2, _In_ BOOLEAN IgnoreCase ); PHLIBAPI BOOLEAN NTAPI PhEqualStringRef( _In_ PPH_STRINGREF String1, _In_ PPH_STRINGREF String2, _In_ BOOLEAN IgnoreCase ); PHLIBAPI ULONG_PTR NTAPI PhFindCharInStringRef( _In_ PPH_STRINGREF String, _In_ WCHAR Character, _In_ BOOLEAN IgnoreCase ); PHLIBAPI ULONG_PTR NTAPI PhFindLastCharInStringRef( _In_ PPH_STRINGREF String, _In_ WCHAR Character, _In_ BOOLEAN IgnoreCase ); PHLIBAPI ULONG_PTR NTAPI PhFindStringInStringRef( _In_ PPH_STRINGREF String, _In_ PPH_STRINGREF SubString, _In_ BOOLEAN IgnoreCase ); PHLIBAPI BOOLEAN NTAPI PhSplitStringRefAtChar( _In_ PPH_STRINGREF Input, _In_ WCHAR Separator, _Out_ PPH_STRINGREF FirstPart, _Out_ PPH_STRINGREF SecondPart ); PHLIBAPI BOOLEAN NTAPI PhSplitStringRefAtLastChar( _In_ PPH_STRINGREF Input, _In_ WCHAR Separator, _Out_ PPH_STRINGREF FirstPart, _Out_ PPH_STRINGREF SecondPart ); PHLIBAPI BOOLEAN NTAPI PhSplitStringRefAtString( _In_ PPH_STRINGREF Input, _In_ PPH_STRINGREF Separator, _In_ BOOLEAN IgnoreCase, _Out_ PPH_STRINGREF FirstPart, _Out_ PPH_STRINGREF SecondPart ); #define PH_SPLIT_AT_CHAR_SET 0x0 // default #define PH_SPLIT_AT_STRING 0x1 #define PH_SPLIT_AT_RANGE 0x2 #define PH_SPLIT_CASE_INSENSITIVE 0x1000 #define PH_SPLIT_COMPLEMENT_CHAR_SET 0x2000 #define PH_SPLIT_START_AT_END 0x4000 #define PH_SPLIT_CHAR_SET_IS_UPPERCASE 0x8000 PHLIBAPI BOOLEAN NTAPI PhSplitStringRefEx( _In_ PPH_STRINGREF Input, _In_ PPH_STRINGREF Separator, _In_ ULONG Flags, _Out_ PPH_STRINGREF FirstPart, _Out_ PPH_STRINGREF SecondPart, _Out_opt_ PPH_STRINGREF SeparatorPart ); #define PH_TRIM_START_ONLY 0x1 #define PH_TRIM_END_ONLY 0x2 PHLIBAPI VOID NTAPI PhTrimStringRef( _Inout_ PPH_STRINGREF String, _In_ PPH_STRINGREF CharSet, _In_ ULONG Flags ); FORCEINLINE LONG PhCompareStringRef2( _In_ PPH_STRINGREF String1, _In_ PWSTR String2, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF sr2; PhInitializeStringRef(&sr2, String2); return PhCompareStringRef(String1, &sr2, IgnoreCase); } FORCEINLINE BOOLEAN PhEqualStringRef2( _In_ PPH_STRINGREF String1, _In_ PWSTR String2, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF sr2; PhInitializeStringRef(&sr2, String2); return PhEqualStringRef(String1, &sr2, IgnoreCase); } FORCEINLINE BOOLEAN PhStartsWithStringRef( _In_ PPH_STRINGREF String, _In_ PPH_STRINGREF Prefix, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF sr; sr.Buffer = String->Buffer; sr.Length = Prefix->Length; if (String->Length < sr.Length) return FALSE; return PhEqualStringRef(&sr, Prefix, IgnoreCase); } FORCEINLINE BOOLEAN PhStartsWithStringRef2( _In_ PPH_STRINGREF String, _In_ PWSTR Prefix, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF prefix; PhInitializeStringRef(&prefix, Prefix); return PhStartsWithStringRef(String, &prefix, IgnoreCase); } FORCEINLINE BOOLEAN PhEndsWithStringRef( _In_ PPH_STRINGREF String, _In_ PPH_STRINGREF Suffix, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF sr; if (Suffix->Length > String->Length) return FALSE; sr.Buffer = (PWCHAR)((PCHAR)String->Buffer + String->Length - Suffix->Length); sr.Length = Suffix->Length; return PhEqualStringRef(&sr, Suffix, IgnoreCase); } FORCEINLINE BOOLEAN PhEndsWithStringRef2( _In_ PPH_STRINGREF String, _In_ PWSTR Suffix, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF suffix; PhInitializeStringRef(&suffix, Suffix); return PhEndsWithStringRef(String, &suffix, IgnoreCase); } FORCEINLINE VOID PhSkipStringRef( _Inout_ PPH_STRINGREF String, _In_ LONG_PTR Length ) { String->Buffer = (PWCH)((PCHAR)String->Buffer + Length); String->Length -= Length; } FORCEINLINE VOID PhReverseStringRef( _In_ PPH_STRINGREF String ) { SIZE_T i; SIZE_T j; WCHAR t; for (i = 0, j = String->Length / sizeof(WCHAR) - 1; i <= j; i++, j--) { t = String->Buffer[i]; String->Buffer[i] = String->Buffer[j]; String->Buffer[j] = t; } } extern PPH_OBJECT_TYPE PhStringType; /** * A 16-bit string object, which supports UTF-16. * * \remarks The \a Length never includes the null terminator. Every string must have a null * terminator at the end, for compatibility reasons. The invariant is: * \code Buffer[Length / sizeof(WCHAR)] = 0 \endcode */ typedef struct _PH_STRING { // Header union { PH_STRINGREF sr; struct { /** The length, in bytes, of the string. */ SIZE_T Length; /** The buffer containing the contents of the string. */ PWCH Buffer; }; }; // Data union { WCHAR Data[1]; struct { /** Reserved. */ ULONG AllocationFlags; /** Reserved. */ PVOID Allocation; }; }; } PH_STRING, *PPH_STRING; PHLIBAPI PPH_STRING NTAPI PhCreateString( _In_ PWSTR Buffer ); PHLIBAPI PPH_STRING NTAPI PhCreateStringEx( _In_opt_ PWCHAR Buffer, _In_ SIZE_T Length ); FORCEINLINE PPH_STRING PhCreateString2( _In_ PPH_STRINGREF String ) { return PhCreateStringEx(String->Buffer, String->Length); } FORCEINLINE PPH_STRING PhCreateStringFromUnicodeString( _In_ PUNICODE_STRING UnicodeString ) { return PhCreateStringEx(UnicodeString->Buffer, UnicodeString->Length); } PHLIBAPI PPH_STRING NTAPI PhReferenceEmptyString( VOID ); PHLIBAPI PPH_STRING NTAPI PhConcatStrings( _In_ ULONG Count, ... ); #define PH_CONCAT_STRINGS_LENGTH_CACHE_SIZE 16 PHLIBAPI PPH_STRING NTAPI PhConcatStrings_V( _In_ ULONG Count, _In_ va_list ArgPtr ); PHLIBAPI PPH_STRING NTAPI PhConcatStrings2( _In_ PWSTR String1, _In_ PWSTR String2 ); PHLIBAPI PPH_STRING NTAPI PhConcatStringRef2( _In_ PPH_STRINGREF String1, _In_ PPH_STRINGREF String2 ); PPH_STRING NTAPI PhConcatStringRef3( _In_ PPH_STRINGREF String1, _In_ PPH_STRINGREF String2, _In_ PPH_STRINGREF String3 ); PHLIBAPI PPH_STRING NTAPI PhFormatString( _In_ _Printf_format_string_ PWSTR Format, ... ); PHLIBAPI PPH_STRING NTAPI PhFormatString_V( _In_ _Printf_format_string_ PWSTR Format, _In_ va_list ArgPtr ); /** * Retrieves a pointer to a string object's buffer or returns NULL. * * \param String A pointer to a string object. * * \return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise * NULL. */ FORCEINLINE PWSTR PhGetString( _In_opt_ PPH_STRING String ) { if (String) return String->Buffer; else return NULL; } FORCEINLINE PH_STRINGREF PhGetStringRef( _In_opt_ PPH_STRING String ) { PH_STRINGREF sr; if (String) sr = String->sr; else PhInitializeEmptyStringRef(&sr); return sr; } /** * Retrieves a pointer to a string object's buffer or returns an empty string. * * \param String A pointer to a string object. * * \return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise an * empty string. */ FORCEINLINE PWSTR PhGetStringOrEmpty( _In_opt_ PPH_STRING String ) { if (String) return String->Buffer; else return L""; } /** * Retrieves a pointer to a string object's buffer or returns the specified alternative string. * * \param String A pointer to a string object. * \param DefaultString The alternative string. * * \return A pointer to the string object's buffer if the supplied pointer is non-NULL, otherwise * the specified alternative string. */ FORCEINLINE PWSTR PhGetStringOrDefault( _In_opt_ PPH_STRING String, _In_ PWSTR DefaultString ) { if (String) return String->Buffer; else return DefaultString; } /** * Determines whether a string is null or empty. * * \param String A pointer to a string object. */ FORCEINLINE BOOLEAN PhIsNullOrEmptyString( _In_opt_ PPH_STRING String ) { return !String || String->Length == 0; } /** * Duplicates a string. * * \param String A string to duplicate. */ FORCEINLINE PPH_STRING PhDuplicateString( _In_ PPH_STRING String ) { return PhCreateStringEx(String->Buffer, String->Length); } /** * Compares two strings. * * \param String1 The first string. * \param String2 The second string. * \param IgnoreCase Whether to ignore character cases. */ FORCEINLINE LONG PhCompareString( _In_ PPH_STRING String1, _In_ PPH_STRING String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) return wcscmp(String1->Buffer, String2->Buffer); else return PhCompareStringRef(&String1->sr, &String2->sr, IgnoreCase); // faster than wcsicmp } /** * Compares two strings. * * \param String1 The first string. * \param String2 The second string. * \param IgnoreCase Whether to ignore character cases. */ FORCEINLINE LONG PhCompareString2( _In_ PPH_STRING String1, _In_ PWSTR String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) { return wcscmp(String1->Buffer, String2); } else { return PhCompareStringRef2(&String1->sr, String2, IgnoreCase); } } /** * Compares two strings, handling NULL strings. * * \param String1 The first string. * \param String2 The second string. * \param IgnoreCase Whether to ignore character cases. */ FORCEINLINE LONG PhCompareStringWithNull( _In_opt_ PPH_STRING String1, _In_opt_ PPH_STRING String2, _In_ BOOLEAN IgnoreCase ) { if (String1 && String2) { return PhCompareString(String1, String2, IgnoreCase); } else if (!String1) { return !String2 ? 0 : -1; } else { return 1; } } /** * Determines whether two strings are equal. * * \param String1 The first string. * \param String2 The second string. * \param IgnoreCase Whether to ignore character cases. */ FORCEINLINE BOOLEAN PhEqualString( _In_ PPH_STRING String1, _In_ PPH_STRING String2, _In_ BOOLEAN IgnoreCase ) { return PhEqualStringRef(&String1->sr, &String2->sr, IgnoreCase); } /** * Determines whether two strings are equal. * * \param String1 The first string. * \param String2 The second string. * \param IgnoreCase Whether to ignore character cases. */ FORCEINLINE BOOLEAN PhEqualString2( _In_ PPH_STRING String1, _In_ PWSTR String2, _In_ BOOLEAN IgnoreCase ) { if (!IgnoreCase) { return wcscmp(String1->Buffer, String2) == 0; } else { return PhEqualStringRef2(&String1->sr, String2, IgnoreCase); } } /** * Determines whether a string starts with another. * * \param String The first string. * \param Prefix The second string. * \param IgnoreCase Whether to ignore character cases. * * \return TRUE if \a String starts with \a Prefix, otherwise FALSE. */ FORCEINLINE BOOLEAN PhStartsWithString( _In_ PPH_STRING String, _In_ PPH_STRING Prefix, _In_ BOOLEAN IgnoreCase ) { return PhStartsWithStringRef(&String->sr, &Prefix->sr, IgnoreCase); } /** * Determines whether a string starts with another. * * \param String The first string. * \param Prefix The second string. * \param IgnoreCase Whether to ignore character cases. * * \return TRUE if \a String starts with \a Prefix, otherwise FALSE. */ FORCEINLINE BOOLEAN PhStartsWithString2( _In_ PPH_STRING String, _In_ PWSTR Prefix, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF prefix; PhInitializeStringRef(&prefix, Prefix); return PhStartsWithStringRef(&String->sr, &prefix, IgnoreCase); } /** * Determines whether a string ends with another. * * \param String The first string. * \param Suffix The second string. * \param IgnoreCase Whether to ignore character cases. * * \return TRUE if \a String ends with \a Suffix, otherwise FALSE. */ FORCEINLINE BOOLEAN PhEndsWithString( _In_ PPH_STRING String, _In_ PPH_STRING Suffix, _In_ BOOLEAN IgnoreCase ) { return PhEndsWithStringRef(&String->sr, &Suffix->sr, IgnoreCase); } /** * Determines whether a string ends with another. * * \param String The first string. * \param Suffix The second string. * \param IgnoreCase Whether to ignore character cases. * * \return TRUE if \a String ends with \a Suffix, otherwise FALSE. */ FORCEINLINE BOOLEAN PhEndsWithString2( _In_ PPH_STRING String, _In_ PWSTR Suffix, _In_ BOOLEAN IgnoreCase ) { PH_STRINGREF suffix; PhInitializeStringRef(&suffix, Suffix); return PhEndsWithStringRef(&String->sr, &suffix, IgnoreCase); } /** * Locates a character in a string. * * \param String The string to search. * \param StartIndex The index, in characters, to start searching at. * \param Char The character to search for. * * \return The index, in characters, of the first occurrence of \a Char in \a String after * \a StartIndex. If \a Char was not found, -1 is returned. */ FORCEINLINE ULONG_PTR PhFindCharInString( _In_ PPH_STRING String, _In_ SIZE_T StartIndex, _In_ WCHAR Char ) { if (StartIndex != 0) { ULONG_PTR r; PH_STRINGREF sr; sr = String->sr; PhSkipStringRef(&sr, StartIndex * sizeof(WCHAR)); r = PhFindCharInStringRef(&sr, Char, FALSE); if (r != -1) return r + StartIndex; else return -1; } else { return PhFindCharInStringRef(&String->sr, Char, FALSE); } } /** * Locates a character in a string, backwards. * * \param String The string to search. * \param StartIndex The index, in characters, to start searching at. * \param Char The character to search for. * * \return The index, in characters, of the last occurrence of \a Char in \a String after * \a StartIndex. If \a Char was not found, -1 is returned. */ FORCEINLINE ULONG_PTR PhFindLastCharInString( _In_ PPH_STRING String, _In_ SIZE_T StartIndex, _In_ WCHAR Char ) { if (StartIndex != 0) { ULONG_PTR r; PH_STRINGREF sr; sr = String->sr; PhSkipStringRef(&sr, StartIndex * sizeof(WCHAR)); r = PhFindLastCharInStringRef(&sr, Char, FALSE); if (r != -1) return r + StartIndex; else return -1; } else { return PhFindLastCharInStringRef(&String->sr, Char, FALSE); } } /** * Locates a string in a string. * * \param String The string to search. * \param StartIndex The index, in characters, to start searching at. * \param SubString The string to search for. * * \return The index, in characters, of the first occurrence of \a SubString in \a String after * \a StartIndex. If \a SubString was not found, -1 is returned. */ FORCEINLINE ULONG_PTR PhFindStringInString( _In_ PPH_STRING String, _In_ SIZE_T StartIndex, _In_ PWSTR SubString ) { PH_STRINGREF sr2; PhInitializeStringRef(&sr2, SubString); if (StartIndex != 0) { ULONG_PTR r; PH_STRINGREF sr1; sr1 = String->sr; PhSkipStringRef(&sr1, StartIndex * sizeof(WCHAR)); r = PhFindStringInStringRef(&sr1, &sr2, FALSE); if (r != -1) return r + StartIndex; else return -1; } else { return PhFindStringInStringRef(&String->sr, &sr2, FALSE); } } /** * Creates a substring of a string. * * \param String The original string. * \param StartIndex The start index, in characters. * \param Count The number of characters to use. */ FORCEINLINE PPH_STRING PhSubstring( _In_ PPH_STRING String, _In_ SIZE_T StartIndex, _In_ SIZE_T Count ) { return PhCreateStringEx(&String->Buffer[StartIndex], Count * sizeof(WCHAR)); } /** * Updates a string object's length with its true length as determined by an embedded null * terminator. * * \param String The string to modify. * * \remarks Use this function after modifying a string object's buffer manually. */ FORCEINLINE VOID PhTrimToNullTerminatorString( _Inout_ PPH_STRING String ) { String->Length = PhCountStringZ(String->Buffer) * sizeof(WCHAR); } // Byte string extern PPH_OBJECT_TYPE PhBytesType; /** * An 8-bit string object, which supports ASCII, UTF-8 and Windows multi-byte encodings, as well as * binary data. */ typedef struct _PH_BYTES { // Header union { PH_BYTESREF br; struct { /** The length, in bytes, of the string. */ SIZE_T Length; /** The buffer containing the contents of the string. */ PCH Buffer; }; }; // Data union { CHAR Data[1]; struct { /** Reserved. */ ULONG AllocationFlags; /** Reserved. */ PVOID Allocation; }; }; } PH_BYTES, *PPH_BYTES; PHLIBAPI PPH_BYTES NTAPI PhCreateBytes( _In_ PSTR Buffer ); PHLIBAPI PPH_BYTES NTAPI PhCreateBytesEx( _In_opt_ PCHAR Buffer, _In_ SIZE_T Length ); FORCEINLINE PPH_BYTES PhCreateBytes2( _In_ PPH_BYTESREF Bytes ) { return PhCreateBytesEx(Bytes->Buffer, Bytes->Length); } // Unicode #define PH_UNICODE_BYTE_ORDER_MARK 0xfeff #define PH_UNICODE_MAX_CODE_POINT 0x10ffff #define PH_UNICODE_UTF16_TO_HIGH_SURROGATE(CodePoint) ((USHORT)((CodePoint) >> 10) + 0xd7c0) #define PH_UNICODE_UTF16_TO_LOW_SURROGATE(CodePoint) ((USHORT)((CodePoint) & 0x3ff) + 0xdc00) #define PH_UNICODE_UTF16_IS_HIGH_SURROGATE(CodeUnit) ((CodeUnit) >= 0xd800 && (CodeUnit) <= 0xdbff) #define PH_UNICODE_UTF16_IS_LOW_SURROGATE(CodeUnit) ((CodeUnit) >= 0xdc00 && (CodeUnit) <= 0xdfff) #define PH_UNICODE_UTF16_TO_CODE_POINT(HighSurrogate, LowSurrogate) (((ULONG)(HighSurrogate) << 10) + (ULONG)(LowSurrogate) - 0x35fdc00) #define PH_UNICODE_UTF8 0 #define PH_UNICODE_UTF16 1 #define PH_UNICODE_UTF32 2 typedef struct _PH_UNICODE_DECODER { UCHAR Encoding; // PH_UNICODE_* UCHAR State; UCHAR InputCount; UCHAR Reserved; union { UCHAR Utf8[4]; USHORT Utf16[2]; ULONG Utf32; } Input; union { struct { UCHAR Input[4]; UCHAR CodeUnit1; UCHAR CodeUnit2; UCHAR CodeUnit3; UCHAR CodeUnit4; } Utf8; struct { USHORT Input[2]; USHORT CodeUnit; } Utf16; struct { ULONG Input; } Utf32; } u; } PH_UNICODE_DECODER, *PPH_UNICODE_DECODER; FORCEINLINE VOID PhInitializeUnicodeDecoder( _Out_ PPH_UNICODE_DECODER Decoder, _In_ UCHAR Encoding ) { memset(Decoder, 0, sizeof(PH_UNICODE_DECODER)); Decoder->Encoding = Encoding; } PHLIBAPI BOOLEAN NTAPI PhWriteUnicodeDecoder( _Inout_ PPH_UNICODE_DECODER Decoder, _In_ ULONG CodeUnit ); PHLIBAPI BOOLEAN NTAPI PhDecodeUnicodeDecoder( _Inout_ PPH_UNICODE_DECODER Decoder, _Out_ PULONG CodePoint ); PHLIBAPI BOOLEAN NTAPI PhEncodeUnicode( _In_ UCHAR Encoding, _In_ ULONG CodePoint, _Out_opt_ PVOID CodeUnits, _Out_ PULONG NumberOfCodeUnits ); // 8-bit to UTF-16 PHLIBAPI VOID NTAPI PhZeroExtendToUtf16Buffer( _In_reads_bytes_(InputLength) PCH Input, _In_ SIZE_T InputLength, _Out_writes_bytes_(InputLength * sizeof(WCHAR)) PWCH Output ); PHLIBAPI PPH_STRING NTAPI PhZeroExtendToUtf16Ex( _In_reads_bytes_(InputLength) PCH Input, _In_ SIZE_T InputLength ); FORCEINLINE PPH_STRING PhZeroExtendToUtf16( _In_ PSTR Input ) { return PhZeroExtendToUtf16Ex(Input, strlen(Input)); } // UTF-16 to ASCII PHLIBAPI PPH_BYTES NTAPI PhConvertUtf16ToAsciiEx( _In_ PWCH Buffer, _In_ SIZE_T Length, _In_opt_ CHAR Replacement ); FORCEINLINE PPH_BYTES PhConvertUtf16ToAscii( _In_ PWSTR Buffer, _In_opt_ CHAR Replacement ) { return PhConvertUtf16ToAsciiEx(Buffer, PhCountStringZ(Buffer) * sizeof(WCHAR), Replacement); } // Multi-byte to UTF-16 // In-place: RtlMultiByteToUnicodeN, RtlMultiByteToUnicodeSize PHLIBAPI PPH_STRING NTAPI PhConvertMultiByteToUtf16( _In_ PSTR Buffer ); PHLIBAPI PPH_STRING NTAPI PhConvertMultiByteToUtf16Ex( _In_ PCHAR Buffer, _In_ SIZE_T Length ); // UTF-16 to multi-byte // In-place: RtlUnicodeToMultiByteN, RtlUnicodeToMultiByteSize PHLIBAPI PPH_BYTES NTAPI PhConvertUtf16ToMultiByte( _In_ PWSTR Buffer ); PHLIBAPI PPH_BYTES NTAPI PhConvertUtf16ToMultiByteEx( _In_ PWCHAR Buffer, _In_ SIZE_T Length ); // UTF-8 to UTF-16 PHLIBAPI BOOLEAN NTAPI PhConvertUtf8ToUtf16Size( _Out_ PSIZE_T BytesInUtf16String, _In_reads_bytes_(BytesInUtf8String) PCH Utf8String, _In_ SIZE_T BytesInUtf8String ); PHLIBAPI BOOLEAN NTAPI PhConvertUtf8ToUtf16Buffer( _Out_writes_bytes_to_(MaxBytesInUtf16String, *BytesInUtf16String) PWCH Utf16String, _In_ SIZE_T MaxBytesInUtf16String, _Out_opt_ PSIZE_T BytesInUtf16String, _In_reads_bytes_(BytesInUtf8String) PCH Utf8String, _In_ SIZE_T BytesInUtf8String ); PHLIBAPI PPH_STRING NTAPI PhConvertUtf8ToUtf16( _In_ PSTR Buffer ); PHLIBAPI PPH_STRING NTAPI PhConvertUtf8ToUtf16Ex( _In_ PCHAR Buffer, _In_ SIZE_T Length ); // UTF-16 to UTF-8 PHLIBAPI BOOLEAN NTAPI PhConvertUtf16ToUtf8Size( _Out_ PSIZE_T BytesInUtf8String, _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String, _In_ SIZE_T BytesInUtf16String ); PHLIBAPI BOOLEAN NTAPI PhConvertUtf16ToUtf8Buffer( _Out_writes_bytes_to_(MaxBytesInUtf8String, *BytesInUtf8String) PCH Utf8String, _In_ SIZE_T MaxBytesInUtf8String, _Out_opt_ PSIZE_T BytesInUtf8String, _In_reads_bytes_(BytesInUtf16String) PWCH Utf16String, _In_ SIZE_T BytesInUtf16String ); PHLIBAPI PPH_BYTES NTAPI PhConvertUtf16ToUtf8( _In_ PWSTR Buffer ); PHLIBAPI PPH_BYTES NTAPI PhConvertUtf16ToUtf8Ex( _In_ PWCHAR Buffer, _In_ SIZE_T Length ); // String builder /** * A string builder structure. * The string builder object allows you to easily construct complex strings without allocating * a great number of strings in the process. */ typedef struct _PH_STRING_BUILDER { /** Allocated length of the string, not including the null terminator. */ SIZE_T AllocatedLength; /** * The constructed string. * \a String will be allocated for \a AllocatedLength, we will modify the \a Length field to be * the correct length. */ PPH_STRING String; } PH_STRING_BUILDER, *PPH_STRING_BUILDER; PHLIBAPI VOID NTAPI PhInitializeStringBuilder( _Out_ PPH_STRING_BUILDER StringBuilder, _In_ SIZE_T InitialCapacity ); PHLIBAPI VOID NTAPI PhDeleteStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder ); PHLIBAPI PPH_STRING NTAPI PhFinalStringBuilderString( _Inout_ PPH_STRING_BUILDER StringBuilder ); PHLIBAPI VOID NTAPI PhAppendStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ PPH_STRINGREF String ); PHLIBAPI VOID NTAPI PhAppendStringBuilder2( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ PWSTR String ); PHLIBAPI VOID NTAPI PhAppendStringBuilderEx( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_opt_ PWCHAR String, _In_ SIZE_T Length ); PHLIBAPI VOID NTAPI PhAppendCharStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ WCHAR Character ); PHLIBAPI VOID NTAPI PhAppendCharStringBuilder2( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ WCHAR Character, _In_ SIZE_T Count ); PHLIBAPI VOID NTAPI PhAppendFormatStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ _Printf_format_string_ PWSTR Format, ... ); VOID NTAPI PhAppendFormatStringBuilder_V( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ _Printf_format_string_ PWSTR Format, _In_ va_list ArgPtr ); PHLIBAPI VOID NTAPI PhInsertStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ SIZE_T Index, _In_ PPH_STRINGREF String ); PHLIBAPI VOID NTAPI PhInsertStringBuilder2( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ SIZE_T Index, _In_ PWSTR String ); PHLIBAPI VOID NTAPI PhInsertStringBuilderEx( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ SIZE_T Index, _In_opt_ PWCHAR String, _In_ SIZE_T Length ); PHLIBAPI VOID NTAPI PhRemoveStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ SIZE_T StartIndex, _In_ SIZE_T Count ); FORCEINLINE VOID PhRemoveEndStringBuilder( _Inout_ PPH_STRING_BUILDER StringBuilder, _In_ SIZE_T Count ) { PhRemoveStringBuilder( StringBuilder, StringBuilder->String->Length / sizeof(WCHAR) - Count, Count ); } // Byte string builder /** * A byte string builder structure. * This is similar to string builder, but is based on PH_BYTES and is suitable for general binary * data. */ typedef struct _PH_BYTES_BUILDER { /** Allocated length of the byte string, not including the null terminator. */ SIZE_T AllocatedLength; /** * The constructed byte string. * \a Bytes will be allocated for \a AllocatedLength, we will modify the \a Length field to be * the correct length. */ PPH_BYTES Bytes; } PH_BYTES_BUILDER, *PPH_BYTES_BUILDER; PHLIBAPI VOID NTAPI PhInitializeBytesBuilder( _Out_ PPH_BYTES_BUILDER BytesBuilder, _In_ SIZE_T InitialCapacity ); PHLIBAPI VOID NTAPI PhDeleteBytesBuilder( _Inout_ PPH_BYTES_BUILDER BytesBuilder ); PHLIBAPI PPH_BYTES NTAPI PhFinalBytesBuilderBytes( _Inout_ PPH_BYTES_BUILDER BytesBuilder ); FORCEINLINE PVOID PhOffsetBytesBuilder( _In_ PPH_BYTES_BUILDER BytesBuilder, _In_ SIZE_T Offset ) { return BytesBuilder->Bytes->Buffer + Offset; } PHLIBAPI VOID NTAPI PhAppendBytesBuilder( _Inout_ PPH_BYTES_BUILDER BytesBuilder, _In_ PPH_BYTESREF Bytes ); PHLIBAPI VOID NTAPI PhAppendBytesBuilder2( _Inout_ PPH_BYTES_BUILDER BytesBuilder, _In_ PCHAR Bytes ); PHLIBAPI PVOID NTAPI PhAppendBytesBuilderEx( _Inout_ PPH_BYTES_BUILDER BytesBuilder, _In_opt_ PVOID Buffer, _In_ SIZE_T Length, _In_opt_ SIZE_T Alignment, _Out_opt_ PSIZE_T Offset ); // Array /** An array structure. Storage is automatically allocated for new elements. */ typedef struct _PH_ARRAY { /** The number of items in the list. */ SIZE_T Count; /** The number of items for which storage is allocated. */ SIZE_T AllocatedCount; /** The size of each item, in bytes. */ SIZE_T ItemSize; /** The base address of the array. */ PVOID Items; } PH_ARRAY, *PPH_ARRAY; FORCEINLINE PVOID PhItemArray( _In_ PPH_ARRAY Array, _In_ SIZE_T Index ) { return (PCHAR)Array->Items + Index * Array->ItemSize; } PHLIBAPI VOID NTAPI PhInitializeArray( _Out_ PPH_ARRAY Array, _In_ SIZE_T ItemSize, _In_ SIZE_T InitialCapacity ); PHLIBAPI VOID NTAPI PhDeleteArray( _Inout_ PPH_ARRAY Array ); PHLIBAPI PVOID NTAPI PhFinalArrayItems( _Inout_ PPH_ARRAY Array ); PHLIBAPI VOID NTAPI PhResizeArray( _Inout_ PPH_ARRAY Array, _In_ SIZE_T NewCapacity ); PHLIBAPI VOID NTAPI PhAddItemArray( _Inout_ PPH_ARRAY Array, _In_ PVOID Item ); PHLIBAPI VOID NTAPI PhAddItemsArray( _Inout_ PPH_ARRAY Array, _In_ PVOID Items, _In_ SIZE_T Count ); PHLIBAPI VOID NTAPI PhClearArray( _Inout_ PPH_ARRAY Array ); PHLIBAPI VOID NTAPI PhRemoveItemArray( _Inout_ PPH_ARRAY Array, _In_ SIZE_T Index ); PHLIBAPI VOID NTAPI PhRemoveItemsArray( _Inout_ PPH_ARRAY Array, _In_ SIZE_T StartIndex, _In_ SIZE_T Count ); // List extern PPH_OBJECT_TYPE PhListType; /** A list structure. Storage is automatically allocated for new elements. */ typedef struct _PH_LIST { /** The number of items in the list. */ ULONG Count; /** The number of items for which storage is allocated. */ ULONG AllocatedCount; /** The array of list items. */ PVOID *Items; } PH_LIST, *PPH_LIST; PHLIBAPI PPH_LIST NTAPI PhCreateList( _In_ ULONG InitialCapacity ); PHLIBAPI VOID NTAPI PhResizeList( _Inout_ PPH_LIST List, _In_ ULONG NewCapacity ); PHLIBAPI VOID NTAPI PhAddItemList( _Inout_ PPH_LIST List, _In_ PVOID Item ); PHLIBAPI VOID NTAPI PhAddItemsList( _Inout_ PPH_LIST List, _In_ PVOID *Items, _In_ ULONG Count ); PHLIBAPI VOID NTAPI PhClearList( _Inout_ PPH_LIST List ); _Success_(return != -1) PHLIBAPI ULONG NTAPI PhFindItemList( _In_ PPH_LIST List, _In_ PVOID Item ); PHLIBAPI VOID NTAPI PhInsertItemList( _Inout_ PPH_LIST List, _In_ ULONG Index, _In_ PVOID Item ); PHLIBAPI VOID NTAPI PhInsertItemsList( _Inout_ PPH_LIST List, _In_ ULONG Index, _In_ PVOID *Items, _In_ ULONG Count ); PHLIBAPI VOID NTAPI PhRemoveItemList( _Inout_ PPH_LIST List, _In_ ULONG Index ); PHLIBAPI VOID NTAPI PhRemoveItemsList( _Inout_ PPH_LIST List, _In_ ULONG StartIndex, _In_ ULONG Count ); /** * A comparison function. * * \param Item1 The first item. * \param Item2 The second item. * \param Context A user-defined value. * * \return * \li A positive value if \a Item1 > \a Item2, * \li A negative value if \a Item1 < \a Item2, and * \li 0 if \a Item1 = \a Item2. */ typedef LONG (NTAPI *PPH_COMPARE_FUNCTION)( _In_ PVOID Item1, _In_ PVOID Item2, _In_opt_ PVOID Context ); // Pointer list extern PPH_OBJECT_TYPE PhPointerListType; /** * A pointer list structure. The pointer list is similar to the normal list structure, but both * insertions and deletions occur in constant time. The list is not ordered. */ typedef struct _PH_POINTER_LIST { /** The number of pointers in the list. */ ULONG Count; /** The number of pointers for which storage is allocated. */ ULONG AllocatedCount; /** Index into pointer array for free list. */ ULONG FreeEntry; /** Index of next usable index into pointer array. */ ULONG NextEntry; /** The array of pointers. */ PVOID *Items; } PH_POINTER_LIST, *PPH_POINTER_LIST; #define PH_IS_LIST_POINTER_VALID(Pointer) (!((ULONG_PTR)(Pointer) & 0x1)) PHLIBAPI PPH_POINTER_LIST NTAPI PhCreatePointerList( _In_ ULONG InitialCapacity ); PHLIBAPI HANDLE NTAPI PhAddItemPointerList( _Inout_ PPH_POINTER_LIST PointerList, _In_ PVOID Pointer ); PHLIBAPI BOOLEAN NTAPI PhEnumPointerListEx( _In_ PPH_POINTER_LIST PointerList, _Inout_ PULONG EnumerationKey, _Out_ PVOID *Pointer, _Out_ PHANDLE PointerHandle ); PHLIBAPI HANDLE NTAPI PhFindItemPointerList( _In_ PPH_POINTER_LIST PointerList, _In_ PVOID Pointer ); PHLIBAPI VOID NTAPI PhRemoveItemPointerList( _Inout_ PPH_POINTER_LIST PointerList, _In_ HANDLE PointerHandle ); FORCEINLINE BOOLEAN PhEnumPointerList( _In_ PPH_POINTER_LIST PointerList, _Inout_ PULONG EnumerationKey, _Out_ PVOID *Pointer ) { while (*EnumerationKey < PointerList->NextEntry) { PVOID pointer = PointerList->Items[*EnumerationKey]; (*EnumerationKey)++; if (PH_IS_LIST_POINTER_VALID(pointer)) { *Pointer = pointer; return TRUE; } } return FALSE; } // Hash typedef struct _PH_HASH_ENTRY { struct _PH_HASH_ENTRY *Next; ULONG Hash; } PH_HASH_ENTRY, *PPH_HASH_ENTRY; #define PH_HASH_SET_INIT { 0 } #define PH_HASH_SET_SIZE(Buckets) (sizeof(Buckets) / sizeof(PPH_HASH_ENTRY)) /** * Initializes a hash set. * * \param Buckets The bucket array. * \param NumberOfBuckets The number of buckets. */ FORCEINLINE VOID PhInitializeHashSet( _Out_ PPH_HASH_ENTRY *Buckets, _In_ ULONG NumberOfBuckets ) { memset(Buckets, 0, sizeof(PPH_HASH_ENTRY) * NumberOfBuckets); } /** * Allocates and initializes a hash set. * * \param NumberOfBuckets The number of buckets. * * \return The allocated hash set. You must free it with PhFree() when you no longer need it. */ FORCEINLINE PPH_HASH_ENTRY * PhCreateHashSet( _In_ ULONG NumberOfBuckets ) { PPH_HASH_ENTRY *buckets; buckets = (PPH_HASH_ENTRY *)PhAllocate(sizeof(PPH_HASH_ENTRY) * NumberOfBuckets); PhInitializeHashSet(buckets, NumberOfBuckets); return buckets; } /** * Determines the number of entries in a hash set. * * \param Buckets The bucket array. * \param NumberOfBuckets The number of buckets. * * \return The number of entries in the hash set. */ FORCEINLINE ULONG PhCountHashSet( _In_ PPH_HASH_ENTRY *Buckets, _In_ ULONG NumberOfBuckets ) { ULONG i; PPH_HASH_ENTRY entry; ULONG count; count = 0; for (i = 0; i < NumberOfBuckets; i++) { for (entry = Buckets[i]; entry; entry = entry->Next) count++; } return count; } /** * Moves entries from one hash set to another. * * \param NewBuckets The new bucket array. * \param NumberOfNewBuckets The number of buckets in \a NewBuckets. * \param OldBuckets The old bucket array. * \param NumberOfOldBuckets The number of buckets in \a OldBuckets. * * \remarks \a NewBuckets and \a OldBuckets must be different. */ FORCEINLINE VOID PhDistributeHashSet( _Inout_ PPH_HASH_ENTRY *NewBuckets, _In_ ULONG NumberOfNewBuckets, _In_ PPH_HASH_ENTRY *OldBuckets, _In_ ULONG NumberOfOldBuckets ) { ULONG i; PPH_HASH_ENTRY entry; PPH_HASH_ENTRY nextEntry; ULONG index; for (i = 0; i < NumberOfOldBuckets; i++) { entry = OldBuckets[i]; while (entry) { nextEntry = entry->Next; index = entry->Hash & (NumberOfNewBuckets - 1); entry->Next = NewBuckets[index]; NewBuckets[index] = entry; entry = nextEntry; } } } /** * Adds an entry to a hash set. * * \param Buckets The bucket array. * \param NumberOfBuckets The number of buckets. * \param Entry The entry. * \param Hash The hash for the entry. * * \remarks This function does not check for duplicates. */ FORCEINLINE VOID PhAddEntryHashSet( _Inout_ PPH_HASH_ENTRY *Buckets, _In_ ULONG NumberOfBuckets, _Out_ PPH_HASH_ENTRY Entry, _In_ ULONG Hash ) { ULONG index; index = Hash & (NumberOfBuckets - 1); Entry->Hash = Hash; Entry->Next = Buckets[index]; Buckets[index] = Entry; } /** * Begins the process of finding an entry in a hash set. * * \param Buckets The bucket array. * \param NumberOfBuckets The number of buckets. * \param Hash The hash for the entry. * * \return The first entry in the chain. * * \remarks If the function returns NULL, the entry does not exist in the hash set. */ FORCEINLINE PPH_HASH_ENTRY PhFindEntryHashSet( _In_ PPH_HASH_ENTRY *Buckets, _In_ ULONG NumberOfBuckets, _In_ ULONG Hash ) { return Buckets[Hash & (NumberOfBuckets - 1)]; } /** * Removes an entry from a hash set. * * \param Buckets The bucket array. * \param NumberOfBuckets The number of buckets. * \param Entry An entry present in the hash set. */ FORCEINLINE VOID PhRemoveEntryHashSet( _Inout_ PPH_HASH_ENTRY *Buckets, _In_ ULONG NumberOfBuckets, _Inout_ PPH_HASH_ENTRY Entry ) { ULONG index; PPH_HASH_ENTRY entry; PPH_HASH_ENTRY previousEntry; index = Entry->Hash & (NumberOfBuckets - 1); previousEntry = NULL; entry = Buckets[index]; do { if (entry == Entry) { if (!previousEntry) Buckets[index] = entry->Next; else previousEntry->Next = entry->Next; return; } previousEntry = entry; entry = entry->Next; } while (entry); // Entry doesn't actually exist in the set. This is a fatal logic error. PhRaiseStatus(STATUS_INTERNAL_ERROR); } /** * Resizes a hash set. * * \param Buckets A pointer to the bucket array. On return the new bucket array is stored in this * variable. * \param NumberOfBuckets A pointer to the number of buckets. On return the new number of buckets is * stored in this variable. * \param NewNumberOfBuckets The new number of buckets. */ FORCEINLINE VOID PhResizeHashSet( _Inout_ PPH_HASH_ENTRY **Buckets, _Inout_ PULONG NumberOfBuckets, _In_ ULONG NewNumberOfBuckets ) { PPH_HASH_ENTRY *newBuckets; newBuckets = PhCreateHashSet(NewNumberOfBuckets); PhDistributeHashSet(newBuckets, NewNumberOfBuckets, *Buckets, *NumberOfBuckets); PhFree(*Buckets); *Buckets = newBuckets; *NumberOfBuckets = NewNumberOfBuckets; } // Hashtable extern PPH_OBJECT_TYPE PhHashtableType; typedef struct _PH_HASHTABLE_ENTRY { /** Hash code of the entry. -1 if entry is unused. */ ULONG HashCode; /** * Either the index of the next entry in the bucket, the index of the next free entry, or -1 for * invalid. */ ULONG Next; /** The beginning of user data. */ QUAD Body; } PH_HASHTABLE_ENTRY, *PPH_HASHTABLE_ENTRY; /** * A comparison function used by a hashtable. * * \param Entry1 The first entry. * \param Entry2 The second entry. * * \return TRUE if the entries are equal, otherwise FALSE. */ typedef BOOLEAN (NTAPI *PPH_HASHTABLE_EQUAL_FUNCTION)( _In_ PVOID Entry1, _In_ PVOID Entry2 ); /** * A hash function used by a hashtable. * * \param Entry The entry. * * \return A hash code for the entry. * * \remarks * \li Two entries which are considered to be equal by the comparison function must be given the * same hash code. * \li Two different entries do not have to be given different hash codes. */ typedef ULONG (NTAPI *PPH_HASHTABLE_HASH_FUNCTION)( _In_ PVOID Entry ); // Use power-of-two sizes instead of primes #define PH_HASHTABLE_POWER_OF_TWO_SIZE // Enables 2^32-1 possible hash codes instead of only 2^31 //#define PH_HASHTABLE_FULL_HASH /** * A hashtable structure. */ typedef struct _PH_HASHTABLE { /** Size of user data in each entry. */ ULONG EntrySize; /** The comparison function. */ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction; /** The hash function. */ PPH_HASHTABLE_HASH_FUNCTION HashFunction; /** The number of allocated buckets. */ ULONG AllocatedBuckets; /** The bucket array. */ PULONG Buckets; /** The number of allocated entries. */ ULONG AllocatedEntries; /** The entry array. */ PVOID Entries; /** Number of entries in the hashtable. */ ULONG Count; /** Index into entry array for free list. */ ULONG FreeEntry; /** * Index of next usable index into entry array, a.k.a. the count of entries that were ever * allocated. */ ULONG NextEntry; } PH_HASHTABLE, *PPH_HASHTABLE; #define PH_HASHTABLE_ENTRY_SIZE(InnerSize) (FIELD_OFFSET(PH_HASHTABLE_ENTRY, Body) + (InnerSize)) #define PH_HASHTABLE_GET_ENTRY(Hashtable, Index) \ ((PPH_HASHTABLE_ENTRY)PTR_ADD_OFFSET((Hashtable)->Entries, \ PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize) * (Index))) #define PH_HASHTABLE_GET_ENTRY_INDEX(Hashtable, Entry) \ ((ULONG)(PTR_ADD_OFFSET(Entry, -(Hashtable)->Entries) / \ PH_HASHTABLE_ENTRY_SIZE((Hashtable)->EntrySize))) PHLIBAPI PPH_HASHTABLE NTAPI PhCreateHashtable( _In_ ULONG EntrySize, _In_ PPH_HASHTABLE_EQUAL_FUNCTION EqualFunction, _In_ PPH_HASHTABLE_HASH_FUNCTION HashFunction, _In_ ULONG InitialCapacity ); PHLIBAPI PVOID NTAPI PhAddEntryHashtable( _Inout_ PPH_HASHTABLE Hashtable, _In_ PVOID Entry ); PHLIBAPI PVOID NTAPI PhAddEntryHashtableEx( _Inout_ PPH_HASHTABLE Hashtable, _In_ PVOID Entry, _Out_opt_ PBOOLEAN Added ); PHLIBAPI VOID NTAPI PhClearHashtable( _Inout_ PPH_HASHTABLE Hashtable ); PHLIBAPI BOOLEAN NTAPI PhEnumHashtable( _In_ PPH_HASHTABLE Hashtable, _Out_ PVOID *Entry, _Inout_ PULONG EnumerationKey ); PHLIBAPI PVOID NTAPI PhFindEntryHashtable( _In_ PPH_HASHTABLE Hashtable, _In_ PVOID Entry ); PHLIBAPI BOOLEAN NTAPI PhRemoveEntryHashtable( _Inout_ PPH_HASHTABLE Hashtable, _In_ PVOID Entry ); // New faster enumeration method typedef struct _PH_HASHTABLE_ENUM_CONTEXT { ULONG_PTR Current; ULONG_PTR End; ULONG_PTR Step; } PH_HASHTABLE_ENUM_CONTEXT, *PPH_HASHTABLE_ENUM_CONTEXT; FORCEINLINE VOID PhBeginEnumHashtable( _In_ PPH_HASHTABLE Hashtable, _Out_ PPH_HASHTABLE_ENUM_CONTEXT Context ) { Context->Current = (ULONG_PTR)Hashtable->Entries; Context->Step = PH_HASHTABLE_ENTRY_SIZE(Hashtable->EntrySize); Context->End = Context->Current + (ULONG_PTR)Hashtable->NextEntry * Context->Step; } FORCEINLINE PVOID PhNextEnumHashtable( _Inout_ PPH_HASHTABLE_ENUM_CONTEXT Context ) { PPH_HASHTABLE_ENTRY entry; while (Context->Current != Context->End) { entry = (PPH_HASHTABLE_ENTRY)Context->Current; Context->Current += Context->Step; if (entry->HashCode != -1) return &entry->Body; } return NULL; } PHLIBAPI ULONG NTAPI PhHashBytes( _In_reads_(Length) PUCHAR Bytes, _In_ SIZE_T Length ); PHLIBAPI ULONG NTAPI PhHashStringRef( _In_ PPH_STRINGREF String, _In_ BOOLEAN IgnoreCase ); FORCEINLINE ULONG PhHashInt32( _In_ ULONG Value ) { // Java style. Value ^= (Value >> 20) ^ (Value >> 12); return Value ^ (Value >> 7) ^ (Value >> 4); } FORCEINLINE ULONG PhHashInt64( _In_ ULONG64 Value ) { // http://www.concentric.net/~Ttwang/tech/inthash.htm Value = ~Value + (Value << 18); Value ^= Value >> 31; Value *= 21; Value ^= Value >> 11; Value += Value << 6; Value ^= Value >> 22; return (ULONG)Value; } FORCEINLINE ULONG PhHashIntPtr( _In_ ULONG_PTR Value ) { #ifdef _WIN64 return PhHashInt64(Value); #else return PhHashInt32(Value); #endif } // Simple hashtable typedef struct _PH_KEY_VALUE_PAIR { PVOID Key; PVOID Value; } PH_KEY_VALUE_PAIR, *PPH_KEY_VALUE_PAIR; PHLIBAPI PPH_HASHTABLE NTAPI PhCreateSimpleHashtable( _In_ ULONG InitialCapacity ); PHLIBAPI PVOID NTAPI PhAddItemSimpleHashtable( _Inout_ PPH_HASHTABLE SimpleHashtable, _In_opt_ PVOID Key, _In_opt_ PVOID Value ); PHLIBAPI PVOID * NTAPI PhFindItemSimpleHashtable( _In_ PPH_HASHTABLE SimpleHashtable, _In_opt_ PVOID Key ); FORCEINLINE PVOID NTAPI PhFindItemSimpleHashtable2( _In_ PPH_HASHTABLE SimpleHashtable, _In_opt_ PVOID Key ) { PVOID *item; item = PhFindItemSimpleHashtable(SimpleHashtable, Key); if (item) return *item; else return NULL; } PHLIBAPI BOOLEAN NTAPI PhRemoveItemSimpleHashtable( _Inout_ PPH_HASHTABLE SimpleHashtable, _In_opt_ PVOID Key ); // Free list typedef struct _PH_FREE_LIST { SLIST_HEADER ListHead; ULONG Count; ULONG MaximumCount; SIZE_T Size; } PH_FREE_LIST, *PPH_FREE_LIST; typedef struct _PH_FREE_LIST_ENTRY { SLIST_ENTRY ListEntry; QUAD_PTR Body; } PH_FREE_LIST_ENTRY, *PPH_FREE_LIST_ENTRY; #ifdef _WIN64 C_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, ListEntry) == 0x0); C_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) == 0x10); #else C_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, ListEntry) == 0x0); C_ASSERT(FIELD_OFFSET(PH_FREE_LIST_ENTRY, Body) == 0x8); #endif PHLIBAPI VOID NTAPI PhInitializeFreeList( _Out_ PPH_FREE_LIST FreeList, _In_ SIZE_T Size, _In_ ULONG MaximumCount ); PHLIBAPI VOID NTAPI PhDeleteFreeList( _Inout_ PPH_FREE_LIST FreeList ); PHLIBAPI PVOID NTAPI PhAllocateFromFreeList( _Inout_ PPH_FREE_LIST FreeList ); PHLIBAPI VOID NTAPI PhFreeToFreeList( _Inout_ PPH_FREE_LIST FreeList, _In_ PVOID Memory ); // Callback /** * A callback function. * * \param Parameter A value given to all callback functions being notified. * \param Context A user-defined value passed to PhRegisterCallback(). */ typedef VOID (NTAPI *PPH_CALLBACK_FUNCTION)( _In_opt_ PVOID Parameter, _In_opt_ PVOID Context ); /** A callback registration structure. */ typedef struct _PH_CALLBACK_REGISTRATION { /** The list entry in the callbacks list. */ LIST_ENTRY ListEntry; /** The callback function. */ PPH_CALLBACK_FUNCTION Function; /** A user-defined value to be passed to the callback function. */ PVOID Context; /** A value indicating whether the registration structure is being used. */ LONG Busy; /** Whether the registration structure is being removed. */ BOOLEAN Unregistering; BOOLEAN Reserved; /** Flags controlling the callback. */ USHORT Flags; } PH_CALLBACK_REGISTRATION, *PPH_CALLBACK_REGISTRATION; /** * A callback structure. The callback object allows multiple callback functions to be registered and * notified in a thread-safe way. */ typedef struct _PH_CALLBACK { /** The list of registered callbacks. */ LIST_ENTRY ListHead; /** A lock protecting the callbacks list. */ PH_QUEUED_LOCK ListLock; /** A condition variable pulsed when the callback becomes free. */ PH_CONDITION BusyCondition; } PH_CALLBACK, *PPH_CALLBACK; #define PH_CALLBACK_DECLARE(Name) PH_CALLBACK Name = { &Name.ListHead, &Name.ListHead, PH_QUEUED_LOCK_INIT, PH_CONDITION_INIT } PHLIBAPI VOID NTAPI PhInitializeCallback( _Out_ PPH_CALLBACK Callback ); PHLIBAPI VOID NTAPI PhDeleteCallback( _Inout_ PPH_CALLBACK Callback ); PHLIBAPI VOID NTAPI PhRegisterCallback( _Inout_ PPH_CALLBACK Callback, _In_ PPH_CALLBACK_FUNCTION Function, _In_opt_ PVOID Context, _Out_ PPH_CALLBACK_REGISTRATION Registration ); PHLIBAPI VOID NTAPI PhRegisterCallbackEx( _Inout_ PPH_CALLBACK Callback, _In_ PPH_CALLBACK_FUNCTION Function, _In_opt_ PVOID Context, _In_ USHORT Flags, _Out_ PPH_CALLBACK_REGISTRATION Registration ); PHLIBAPI VOID NTAPI PhUnregisterCallback( _Inout_ PPH_CALLBACK Callback, _Inout_ PPH_CALLBACK_REGISTRATION Registration ); PHLIBAPI VOID NTAPI PhInvokeCallback( _In_ PPH_CALLBACK Callback, _In_opt_ PVOID Parameter ); // General PHLIBAPI ULONG NTAPI PhGetPrimeNumber( _In_ ULONG Minimum ); PHLIBAPI ULONG NTAPI PhRoundUpToPowerOfTwo( _In_ ULONG Number ); PHLIBAPI ULONG NTAPI PhExponentiate( _In_ ULONG Base, _In_ ULONG Exponent ); PHLIBAPI ULONG64 NTAPI PhExponentiate64( _In_ ULONG64 Base, _In_ ULONG Exponent ); PHLIBAPI BOOLEAN NTAPI PhHexStringToBuffer( _In_ PPH_STRINGREF String, _Out_writes_bytes_(String->Length / sizeof(WCHAR) / 2) PUCHAR Buffer ); PHLIBAPI PPH_STRING NTAPI PhBufferToHexString( _In_reads_bytes_(Length) PUCHAR Buffer, _In_ ULONG Length ); PPH_STRING NTAPI PhBufferToHexStringEx( _In_reads_bytes_(Length) PUCHAR Buffer, _In_ ULONG Length, _In_ BOOLEAN UpperCase ); PHLIBAPI BOOLEAN NTAPI PhStringToInteger64( _In_ PPH_STRINGREF String, _In_opt_ ULONG Base, _Out_opt_ PLONG64 Integer ); PHLIBAPI BOOLEAN NTAPI PhStringToDouble( _In_ PPH_STRINGREF String, _Reserved_ ULONG Base, _Out_opt_ DOUBLE *Double ); PHLIBAPI PPH_STRING NTAPI PhIntegerToString64( _In_ LONG64 Integer, _In_opt_ ULONG Base, _In_ BOOLEAN Signed ); #define PH_TIMESPAN_STR_LEN 30 #define PH_TIMESPAN_STR_LEN_1 (PH_TIMESPAN_STR_LEN + 1) #define PH_TIMESPAN_HMS 0 #define PH_TIMESPAN_HMSM 1 #define PH_TIMESPAN_DHMS 2 PHLIBAPI VOID NTAPI PhPrintTimeSpan( _Out_writes_(PH_TIMESPAN_STR_LEN_1) PWSTR Destination, _In_ ULONG64 Ticks, _In_opt_ ULONG Mode ); PHLIBAPI VOID NTAPI PhFillMemoryUlong( _Inout_updates_(Count) _Needs_align_(4) PULONG Memory, _In_ ULONG Value, _In_ SIZE_T Count ); PHLIBAPI VOID NTAPI PhDivideSinglesBySingle( _Inout_updates_(Count) PFLOAT A, _In_ FLOAT B, _In_ SIZE_T Count ); // Auto-dereference convenience functions FORCEINLINE PPH_STRING PhaCreateString( _In_ PWSTR Buffer ) { return PH_AUTO_T(PH_STRING, PhCreateString(Buffer)); } FORCEINLINE PPH_STRING PhaCreateStringEx( _In_opt_ PWSTR Buffer, _In_ SIZE_T Length ) { return PH_AUTO_T(PH_STRING, PhCreateStringEx(Buffer, Length)); } FORCEINLINE PPH_STRING PhaDuplicateString( _In_ PPH_STRING String ) { return PH_AUTO_T(PH_STRING, PhDuplicateString(String)); } FORCEINLINE PPH_STRING PhaConcatStrings( _In_ ULONG Count, ... ) { va_list argptr; va_start(argptr, Count); return PH_AUTO_T(PH_STRING, PhConcatStrings_V(Count, argptr)); } FORCEINLINE PPH_STRING PhaConcatStrings2( _In_ PWSTR String1, _In_ PWSTR String2 ) { return PH_AUTO_T(PH_STRING, PhConcatStrings2(String1, String2)); } FORCEINLINE PPH_STRING PhaFormatString( _In_ _Printf_format_string_ PWSTR Format, ... ) { va_list argptr; va_start(argptr, Format); return PH_AUTO_T(PH_STRING, PhFormatString_V(Format, argptr)); } FORCEINLINE PPH_STRING PhaLowerString( _In_ PPH_STRING String ) { PPH_STRING newString; newString = PhaDuplicateString(String); _wcslwr(newString->Buffer); return newString; } FORCEINLINE PPH_STRING PhaUpperString( _In_ PPH_STRING String ) { PPH_STRING newString; newString = PhaDuplicateString(String); _wcsupr(newString->Buffer); return newString; } FORCEINLINE PPH_STRING PhaSubstring( _In_ PPH_STRING String, _In_ SIZE_T StartIndex, _In_ SIZE_T Count ) { return PH_AUTO_T(PH_STRING, PhSubstring(String, StartIndex, Count)); } // Format typedef enum _PH_FORMAT_TYPE { CharFormatType, StringFormatType, StringZFormatType, MultiByteStringFormatType, MultiByteStringZFormatType, Int32FormatType, Int64FormatType, IntPtrFormatType, UInt32FormatType, UInt64FormatType, UIntPtrFormatType, DoubleFormatType, SizeFormatType, FormatTypeMask = 0x3f, /** If not specified, for floating-point 6 is assumed **/ FormatUsePrecision = 0x40, /** If not specified, ' ' is assumed */ FormatUsePad = 0x80, /** If not specified, 10 is assumed */ FormatUseRadix = 0x100, /** If not specified, the default value is assumed */ FormatUseParameter = 0x200, // Floating-point flags /** Use standard form instead of normal form */ FormatStandardForm = 0x1000, /** Use hexadecimal form instead of normal form */ FormatHexadecimalForm = 0x2000, /** Reserved */ FormatForceDecimalPoint = 0x4000, /** Trailing zeros and possibly the decimal point are trimmed */ FormatCropZeros = 0x8000, // Floating-point and integer flags /** Group digits (with floating-point, only works when in normal form) */ FormatGroupDigits = 0x10000, /** Always insert a prefix, '+' for positive and '-' for negative */ FormatPrefixSign = 0x20000, /** * Pad left with zeros, taking into consideration the sign. Width must be specified. * Format*Align cannot be used in conjunction with this flag. If FormatGroupDigits is specified, * this flag is ignored. */ FormatPadZeros = 0x40000, // General flags /** Applies left alignment. Width must be specified. */ FormatLeftAlign = 0x80000000, /** Applies right alignment. Width must be specified. */ FormatRightAlign = 0x40000000, /** Make characters uppercase (only available for some types) */ FormatUpperCase = 0x20000000 } PH_FORMAT_TYPE; /** Describes an element to be formatted to a string. */ typedef struct _PH_FORMAT { /** Specifies the type of the element and optional flags. */ PH_FORMAT_TYPE Type; /** * The precision of the element. The meaning of this field depends on the element type. For * \a Double and \a Size, this field specifies the number of decimal points to include. */ USHORT Precision; /** * The width of the element. This field specifies the minimum number of characters to output. * The remaining space is padded with either spaces, zeros, or a custom character. */ USHORT Width; /** The pad character. */ WCHAR Pad; /** * The meaning of this field depends on the element type. For integer types, this field * specifies the base to convert the number into. For \a Size, this field specifies the maximum * size unit. */ UCHAR Radix; /** * The meaning of this field depends on the element type. For \a Size, this field specifies the * minimum size unit. */ UCHAR Parameter; union { WCHAR Char; PH_STRINGREF String; PWSTR StringZ; PH_BYTESREF MultiByteString; PSTR MultiByteStringZ; LONG Int32; LONG64 Int64; LONG_PTR IntPtr; ULONG UInt32; ULONG64 UInt64; ULONG_PTR UIntPtr; DOUBLE Double; ULONG64 Size; } u; } PH_FORMAT, *PPH_FORMAT; // Convenience macros #define PhInitFormatC(f, v) do { (f)->Type = CharFormatType; (f)->u.Char = (v); } while (0) #define PhInitFormatS(f, v) do { (f)->Type = StringFormatType; PhInitializeStringRef(&(f)->u.String, (v)); } while (0) #define PhInitFormatSR(f, v) do { (f)->Type = StringFormatType; (f)->u.String = (v); } while (0) #define PhInitFormatMultiByteS(f, v) do { (f)->Type = MultiByteStringFormatType; PhInitializeBytesRef(&(f)->u.MultiByteString, (v)); } while (0) #define PhInitFormatD(f, v) do { (f)->Type = Int32FormatType; (f)->u.Int32 = (v); } while (0) #define PhInitFormatU(f, v) do { (f)->Type = UInt32FormatType; (f)->u.UInt32 = (v); } while (0) #define PhInitFormatX(f, v) do { (f)->Type = UInt32FormatType | FormatUseRadix; (f)->u.UInt32 = (v); (f)->Radix = 16; } while (0) #define PhInitFormatI64D(f, v) do { (f)->Type = Int64FormatType; (f)->u.Int64 = (v); } while (0) #define PhInitFormatI64U(f, v) do { (f)->Type = UInt64FormatType; (f)->u.UInt64 = (v); } while (0) #define PhInitFormatI64X(f, v) do { (f)->Type = UInt64FormatType | FormatUseRadix; (f)->u.UInt64 = (v); (f)->Radix = 16; } while (0) #define PhInitFormatIU(f, v) do { (f)->Type = UIntPtrFormatType; (f)->u.UIntPtr = (v); } while (0) #define PhInitFormatIX(f, v) do { (f)->Type = UIntPtrFormatType | FormatUseRadix; (f)->u.UIntPtr = (v); (f)->Radix = 16; } while (0) #define PhInitFormatF(f, v, p) do { (f)->Type = DoubleFormatType | FormatUsePrecision; (f)->u.Double = (v); (f)->Precision = (p); } while (0) #define PhInitFormatE(f, v, p) do { (f)->Type = DoubleFormatType | FormatStandardForm | FormatUsePrecision; (f)->u.Double = (v); (f)->Precision = (p); } while (0) #define PhInitFormatA(f, v, p) do { (f)->Type = DoubleFormatType | FormatHexadecimalForm | FormatUsePrecision; (f)->u.Double = (v); (f)->Precision = (p); } while (0) #define PhInitFormatSize(f, v) do { (f)->Type = SizeFormatType; (f)->u.Size = (v); } while (0) PHLIBAPI PPH_STRING NTAPI PhFormat( _In_reads_(Count) PPH_FORMAT Format, _In_ ULONG Count, _In_opt_ SIZE_T InitialCapacity ); PHLIBAPI BOOLEAN NTAPI PhFormatToBuffer( _In_reads_(Count) PPH_FORMAT Format, _In_ ULONG Count, _Out_writes_bytes_opt_(BufferLength) PWSTR Buffer, _In_opt_ SIZE_T BufferLength, _Out_opt_ PSIZE_T ReturnLength ); // error PHLIBAPI ULONG NTAPI PhNtStatusToDosError( _In_ NTSTATUS Status ); PHLIBAPI NTSTATUS NTAPI PhDosErrorToNtStatus( _In_ ULONG DosError ); PHLIBAPI BOOLEAN NTAPI PhNtStatusFileNotFound( _In_ NTSTATUS Status ); // Generic tree definitions typedef enum _PH_TREE_ENUMERATION_ORDER { TreeEnumerateInOrder, TreeEnumerateInReverseOrder } PH_TREE_ENUMERATION_ORDER; #define PhIsLeftChildElement(Links) ((Links)->Parent->Left == (Links)) #define PhIsRightChildElement(Links) ((Links)->Parent->Right == (Links)) // avltree typedef struct _PH_AVL_LINKS { struct _PH_AVL_LINKS *Parent; struct _PH_AVL_LINKS *Left; struct _PH_AVL_LINKS *Right; LONG Balance; } PH_AVL_LINKS, *PPH_AVL_LINKS; struct _PH_AVL_TREE; typedef LONG (NTAPI *PPH_AVL_TREE_COMPARE_FUNCTION)( _In_ PPH_AVL_LINKS Links1, _In_ PPH_AVL_LINKS Links2 ); typedef struct _PH_AVL_TREE { PH_AVL_LINKS Root; // Right contains real root ULONG Count; PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction; } PH_AVL_TREE, *PPH_AVL_TREE; #define PH_AVL_TREE_INIT(CompareFunction) { { NULL, NULL, NULL, 0 }, 0, CompareFunction } #define PhRootElementAvlTree(Tree) ((Tree)->Root.Right) PHLIBAPI VOID NTAPI PhInitializeAvlTree( _Out_ PPH_AVL_TREE Tree, _In_ PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction ); PHLIBAPI PPH_AVL_LINKS NTAPI PhAddElementAvlTree( _Inout_ PPH_AVL_TREE Tree, _Out_ PPH_AVL_LINKS Element ); PHLIBAPI VOID NTAPI PhRemoveElementAvlTree( _Inout_ PPH_AVL_TREE Tree, _Inout_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhFindElementAvlTree( _In_ PPH_AVL_TREE Tree, _In_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhLowerBoundElementAvlTree( _In_ PPH_AVL_TREE Tree, _In_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhUpperBoundElementAvlTree( _In_ PPH_AVL_TREE Tree, _In_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhLowerDualBoundElementAvlTree( _In_ PPH_AVL_TREE Tree, _In_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhUpperDualBoundElementAvlTree( _In_ PPH_AVL_TREE Tree, _In_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhMinimumElementAvlTree( _In_ PPH_AVL_TREE Tree ); PHLIBAPI PPH_AVL_LINKS NTAPI PhMaximumElementAvlTree( _In_ PPH_AVL_TREE Tree ); PHLIBAPI PPH_AVL_LINKS NTAPI PhSuccessorElementAvlTree( _In_ PPH_AVL_LINKS Element ); PHLIBAPI PPH_AVL_LINKS NTAPI PhPredecessorElementAvlTree( _In_ PPH_AVL_LINKS Element ); typedef BOOLEAN (NTAPI *PPH_ENUM_AVL_TREE_CALLBACK)( _In_ PPH_AVL_TREE Tree, _In_ PPH_AVL_LINKS Element, _In_opt_ PVOID Context ); PHLIBAPI VOID NTAPI PhEnumAvlTree( _In_ PPH_AVL_TREE Tree, _In_ PH_TREE_ENUMERATION_ORDER Order, _In_ PPH_ENUM_AVL_TREE_CALLBACK Callback, _In_opt_ PVOID Context ); #ifdef __cplusplus } #endif #endif