/*
 *  kexbases\ntdll\rtl.c
 *
 *  Copyright (C) 2013, Ley0k
 *  Copyright (C) 2019, jumper
 *
 *  This file is part of KernelEx source code.
 *
 *  KernelEx is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published
 *  by the Free Software Foundation; version 2 of the License.
 *
 *  KernelEx is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "ntstatus.h"
#include "common.h"
#include "_ntdll_apilist.h"
#include "../kernel32/_kernel32_apilist.h"
//#include <limits.h>

typedef LONG NTSTATUS;


/* MAKE~EXPORT NlsMbOemCodePageTag_bool=NlsMbOemCodePageTag */
// FIXME: for removed code?  WDK 3.51+
bool NlsMbOemCodePageTag_bool = false;



/* MAKE_EXPORT RtlAdjustPrivilege=RtlAdjustPrivilege */

NTSTATUS NTAPI RtlAdjustPrivilege (
	IN ULONG Privilege,
	IN BOOLEAN NewValue,
	IN BOOLEAN ForThread,
	OUT PBOOLEAN OldValue)
{
	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlCopySid=RtlCopySid */

NTSTATUS RtlCopySid (
	IN ULONG BufferLength,
	IN PSID Dest,
	IN PSID Src
)
{
	ULONG SidLength;

	SidLength = RtlLengthSid (Src);

	if (SidLength > BufferLength)
		return STATUS_BUFFER_TOO_SMALL;

	RtlMoveMemory (Dest, Src, SidLength);
	return STATUS_SUCCESS;
}



/* MAKE~EXPORT RtlCreateEnvironment=RtlCreateEnvironment */
// use stub until implemented

NTSTATUS RtlCreateEnvironment (IN BOOLEAN Inherit,
					 OUT PVOID *Environment
)
{
	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlCreateSecurityDescriptor=RtlCreateSecurityDescriptor */

NTSTATUS RtlCreateSecurityDescriptor (
	IN PSECURITY_DESCRIPTOR SecurityDescriptor,
	IN ULONG Revision 
) 		
{
	PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;

	if (Revision != SECURITY_DESCRIPTOR_REVISION)
		return STATUS_UNKNOWN_REVISION;

	RtlZeroMemory (Sd, sizeof (*Sd));
	Sd->Revision = SECURITY_DESCRIPTOR_REVISION;

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlCreateTagHeap=RtlCreateTagHeap */

ULONG RtlCreateTagHeap (IN HANDLE HeapHandle,
		IN ULONG Flags,
		IN PWSTR TagName,
		IN PWSTR TagSubName 
)
{
	return TRUE;
}



/* MAKE_EXPORT RtlCreateUserThread=RtlCreateUserThread */

NTSTATUS RtlCreateUserThread (
	IN HANDLE ProcessHandle,
	IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
	IN BOOLEAN CreateSuspended,
	IN ULONG StackZeroBits,
	IN OUT PULONG StackReserved,
	IN OUT PULONG StackCommit,
	IN PVOID StartAddress,
	IN PVOID StartParameter OPTIONAL,
	OUT PHANDLE ThreadHandle,
	OUT PCLIENT_ID ClientID
)
{
	DWORD dwProcessId;
	DWORD dwThreadId;

	dwProcessId = GetProcessId_new (ProcessHandle);

	if (dwProcessId == 0)
		return STATUS_INVALID_PARAMETER;

	*ThreadHandle = CreateRemoteThread_new (
    ProcessHandle,
    NULL,
    *StackCommit,
    (LPTHREAD_START_ROUTINE)StartAddress,
    StartParameter,
    CreateSuspended ? CREATE_SUSPENDED : 0,
    &dwThreadId
    );

	if (dwThreadId == 0)
		return GetLastError ();

	ClientID->UniqueProcessId = dwProcessId;
	ClientID->UniqueThreadId = dwThreadId;

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlDeleteCriticalSection_new=RtlDeleteCriticalSection */

NTSTATUS RtlDeleteCriticalSection_new (
	RTL_CRITICAL_SECTION *crit
)
{
	__try
	{
		DeleteCriticalSection (crit);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return STATUS_INVALID_ADDRESS;
	}

	return STATUS_SUCCESS;
}



/* MAKE~EXPORT RtlDosPathNameToNtPathName_U=RtlDosPathNameToNtPathName_U *

BOOLEAN RtlDosPathNameToNtPathName_U (
	IN PCWSTR DosName,
	OUT PUNICODE_STRING NtName,
	OUT PCWSTR *PartName,
	OUT PVOID RelativeName
)
{
	DWORD dwLength;
	DWORD result;

	if (IsBadUnicodeStringPtr (DosName, -1) ||
	   IsBadWritePtr (NtName, sizeof (UNICODE_STRING)) ||
	   IsBadWritePtr (PartName, sizeof (DWORD)) ||
	   IsBadUnicodeStringPtr (*PartName, -1))
		return FALSE;

	dwLength = wcslen (DosName);

	NtName->Buffer = (PWSTR)malloc (dwLength);

	result = GetLongPathNameW (DosName,
								NtName->Buffer,
								dwLength);

	if (!result)
	{
		free (NtName->Buffer);
		return FALSE;
	}

	return TRUE;
} */



/* MAKE_EXPORT RtlEnterCriticalSection_new=RtlEnterCriticalSection */

NTSTATUS RtlEnterCriticalSection_new (
	RTL_CRITICAL_SECTION *crit
)
{
	__try
	{
		EnterCriticalSection (crit);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return STATUS_INVALID_ADDRESS;
	}

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlFreeSid=RtlFreeSid */

PVOID RtlFreeSid (IN PSID Sid)
{
	RtlZeroMemory (Sid, sizeof (SID));
	return NULL;
}



/* MAKE_EXPORT RtlInitializeBitMap=RtlInitializeBitMap */

VOID RtlInitializeBitMap (
	OUT PRTL_BITMAP BitMapHeader,
	IN PULONG BitMapBuffer,
	IN ULONG SizeOfBitMap
)
{
	BitMapHeader->SizeOfBitMap = SizeOfBitMap;
	BitMapHeader->Buffer = BitMapBuffer;
}



/* MAKE_EXPORT RtlInitializeCriticalSection_new=RtlInitializeCriticalSection */

NTSTATUS RtlInitializeCriticalSection_new (
	RTL_CRITICAL_SECTION *crit
)
{
	__try
	{
		InitializeCriticalSection (crit);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return STATUS_INVALID_ADDRESS;
	}

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlInitializeCriticalSectionAndSpinCount_new=RtlInitializeCriticalSectionAndSpinCount */

NTSTATUS RtlInitializeCriticalSectionAndSpinCount_new (
	RTL_CRITICAL_SECTION *crit,
	ULONG spincount
)
{
	return RtlInitializeCriticalSection_new (crit);
}



/* MAKE_EXPORT RtlInitializeCriticalSectionEx_new=RtlInitializeCriticalSectionEx */

NTSTATUS RtlInitializeCriticalSectionEx_new (
	RTL_CRITICAL_SECTION *crit,
	ULONG spincount,
	ULONG flags
)
{
	return RtlInitializeCriticalSection_new (crit);
}



/* MAKE_EXPORT RtlInitializeSid=RtlInitializeSid */

NTSTATUS RtlInitializeSid (
	IN PSID Sid,
	IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
	IN UCHAR SubAuthorityCount
)
{
    PISID ISid = (PISID)Sid;

    ISid->Revision = SID_REVISION;
    ISid->SubAuthorityCount = SubAuthorityCount;
    ISid->IdentifierAuthority = *IdentifierAuthority;

    return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlLeaveCriticalSection_new=RtlLeaveCriticalSection */

NTSTATUS RtlLeaveCriticalSection_new (
	RTL_CRITICAL_SECTION *crit
)
{
	__try
	{
		LeaveCriticalSection (crit);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return STATUS_INVALID_ADDRESS;
	}

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlLengthRequiredSid=RtlLengthRequiredSid */

ULONG RtlLengthRequiredSid (IN ULONG SubAuthorityCount)
{
	return (ULONG)FIELD_OFFSET (SID,
							SubAuthority[SubAuthorityCount]);
}



/* MAKE_EXPORT RtlLengthSid=RtlLengthSid */

ULONG RtlLengthSid (IN PSID Sid)
{
	PISID ISid = (PISID)Sid;

	return (ULONG)FIELD_OFFSET (SID,
							SubAuthority[ISid->SubAuthorityCount]);
}



/* MAKE_EXPORT RtlRaiseStatus=RtlRaiseStatus */

VOID RtlRaiseStatus (IN NTSTATUS Status)
// See www.codewarrior.cn for change
{
	//DWORD dwError = RtlNtStatusToDosError (Status);

	RaiseException (Status, //dwError,
				0,
				0,
				NULL);
}



/* MAKE_EXPORT RtlSubAuthoritySid=RtlSubAuthoritySid */

PULONG RtlSubAuthoritySid (
	IN PSID Sid,
	IN ULONG SubAuthority
)
{
    PISID ISid = (PISID)Sid;

    /* Return the offset */
    return (PULONG)&ISid->SubAuthority[SubAuthority];
}



/* MAKE_EXPORT RtlSystemTimeToLocalTime=RtlSystemTimeToLocalTime */

NTSTATUS RtlSystemTimeToLocalTime (
	IN PLARGE_INTEGER SystemTime,
	OUT PLARGE_INTEGER LocalTime
)
{
	FILETIME FileTime, LocalFileTime;
	SYSTEMTIME cSystemTime;

	GetSystemTime (&cSystemTime);
	SystemTimeToFileTime (&cSystemTime, &FileTime);

	FileTimeToLocalFileTime (&FileTime, &LocalFileTime);

	LocalTime->QuadPart = LocalFileTime.dwLowDateTime +
						  LocalFileTime.dwHighDateTime;

	return STATUS_SUCCESS;
}



/* MAKE_EXPORT RtlTryEnterCriticalSection_new=RtlTryEnterCriticalSection */

NTSTATUS RtlTryEnterCriticalSection_new (
	RTL_CRITICAL_SECTION *crit
)
{
	__try
	{
		TryEnterCriticalSection_new (crit);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return STATUS_INVALID_ADDRESS;
	}

	return STATUS_SUCCESS;
}



#define TICKSPERSEC 10000000
#define TICKSTO1970 0x019db1ded53e8000
#define TICKSTO1980 0x01a8e79fe1d58000

/* MAKE_EXPORT RtlTimeToSecondsSince1970_new=RtlTimeToSecondsSince1970 */

BOOL NTAPI RtlTimeToSecondsSince1970_new (
  IN  PLARGE_INTEGER pliTime,
  OUT PULONG pSecondsSince1970
)
{
  LARGE_INTEGER liSeconds;
  liSeconds.QuadPart = (pliTime->QuadPart - TICKSTO1970) / TICKSPERSEC;
  if (liSeconds.HighPart != 0)
    return FALSE;
  *pSecondsSince1970 = liSeconds.LowPart;
  return TRUE;
}


/* MAKE_EXPORT RtlTimeToSecondsSince1980_new=RtlTimeToSecondsSince1980 */

BOOL NTAPI RtlTimeToSecondsSince1980_new (
  IN  PLARGE_INTEGER pliTime,
  OUT PULONG pSecondsSince1980
)
{
  LARGE_INTEGER liSeconds;
  liSeconds.QuadPart = (pliTime->QuadPart - TICKSTO1980) / TICKSPERSEC;
  if (liSeconds.HighPart != 0)
    return FALSE;
  *pSecondsSince1980 = liSeconds.LowPart;
  return TRUE;
}



/* MAKE_EXPORT RtlSecondsSince1970ToTime_new=RtlSecondsSince1970ToTime */

VOID NTAPI RtlSecondsSince1970ToTime_new (
  IN  ULONG uSecondsSince1970,
  OUT PLARGE_INTEGER pliTime
)
{
  pliTime->QuadPart = ((LONGLONG)uSecondsSince1970 * TICKSPERSEC) + TICKSTO1970;
}



/* MAKE_EXPORT RtlSecondsSince1980ToTime_new=RtlSecondsSince1980ToTime */

VOID NTAPI RtlSecondsSince1980ToTime_new (
  IN  ULONG uSecondsSince1980,
  OUT PLARGE_INTEGER pliTime
)
{
  pliTime->QuadPart = ((LONGLONG)uSecondsSince1980 * TICKSPERSEC) + TICKSTO1980;
}


#if 0
/* MAKE~EXPORT RtlFillMemory_fwd=RtlFillMemory */

void RtlFillMemory_fwd (
  PVOID Dest,
  SIZE_T Length,
  BYTE Fill
)
{
	RtlFillMemory (Dest, Length, Fill);
}



/* MAKE~EXPORT RtlMoveMemory_fwd=RtlMoveMemory */

void RtlMoveMemory_fwd (
  PVOID Dest,
  const VOID* Src,
  SIZE_T Length
)
{
	RtlMoveMemory (Dest, Src, Length);
}


//#undef RtlZeroMemory
//extern RtlZeroMemory(PVOID Dest, SIZE_T Length);


/* MAKE~EXPORT RtlZeroMemory_fwd=RtlZeroMemory */

void RtlZeroMemory_fwd (
  PVOID Dest,
  SIZE_T Length
)
{
	RtlZeroMemory (Dest, Length);
}
#endif


/* MAKE_EXPORT RtlInterlockedCompareExchange64_new=RtlInterlockedCompareExchange64 */

LONGLONG WINAPI RtlInterlockedCompareExchange64_new (LONGLONG *dest, LONGLONG xchg, LONGLONG comp)
{ LONGLONG orig;

  if ((orig= *dest) == comp)
    *dest = xchg;
  return orig;
}


// sdk/lib/rtl/critical.c
//RtlIsCriticalSectionLocked 5.2
//RtlIsCriticalSectionLockedByThread 5.2
