#include "RBC9-SpaceNav.h"
#include "stdio.h"


#pragma warning(disable : 4996)

HANDLE RBC9_Open_Reg(IN PWSTR basekey,IN PWSTR subkey)
{
	WCHAR				buf[256];
	UNICODE_STRING		path;
	OBJECT_ATTRIBUTES	obj_attr;
	HANDLE				key;
	NTSTATUS			Status;

	//	DBG_ENTER(("\"%ws\"", subkey));

	RtlZeroMemory(buf, sizeof(buf));
	path.Length = 0;
	path.MaximumLength = sizeof(buf);
	path.Buffer = buf;

	RtlAppendUnicodeToString(&path, basekey);
	RtlAppendUnicodeToString(&path, L"\\Layout\\");
	RtlAppendUnicodeToString(&path, subkey);

	DBG_OUT(("newpath bis %ws", path.Buffer));

	InitializeObjectAttributes(&obj_attr, &path,
		OBJ_CASE_INSENSITIVE, NULL, NULL);

	Status = ZwOpenKey(&key, KEY_ALL_ACCESS, &obj_attr);
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("NULL: ZwOpenKey failed: %x", Status));
		return NULL;
	}

	//	DBG_LEAVE(("%p", key));
	return key;
}

NTSTATUS RBC9_Get_Key_Info(HANDLE key,unsigned int *NbrSubKey,unsigned int *NbrValue)
{
	NTSTATUS				Status;
	PKEY_FULL_INFORMATION	MyKeyInfo;
	ULONG					size;

	//DBG_ENTER((""));

	Status = ZwQueryKey (key,KeyFullInformation,NULL,0,&size);
	if(! NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 
	{
		DBG_LEAVE(("%x", Status));
		return Status;
	}

	MyKeyInfo = (PKEY_FULL_INFORMATION)ExAllocatePool(NonPagedPool, size);
	if(MyKeyInfo == NULL) {

		DBG_LEAVE(("STATUS_INSUFFICIENT_RESOURCES"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	Status = ZwQueryKey (key,KeyFullInformation,MyKeyInfo,size,&size);
	if(! NT_SUCCESS(Status)) 
	{
		ExFreePool(MyKeyInfo);
		DBG_LEAVE(("%x", Status));
		return Status;
	}

	if (NbrSubKey != NULL)
		*NbrSubKey = MyKeyInfo->SubKeys;
	if (NbrValue != NULL)
		*NbrValue = MyKeyInfo->Values;

	//DBG_LEAVE(("MyKeyList %d %d",MyKeyInfo->SubKeys,MyKeyInfo->MaxNameLen));

	return STATUS_SUCCESS;
}
NTSTATUS RBC9_Get_SubKey_Name(HANDLE key,unsigned int Num_SubKey,WCHAR *buf,ULONG bufsize)
{

	NTSTATUS				Status;
	ULONG					size;
	PKEY_BASIC_INFORMATION	MySubKeyInfo;

	//	DBG_ENTER((""));

	Status = ZwEnumerateKey  (key,Num_SubKey,KeyBasicInformation,NULL,0,&size);
	if(! NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 
	{
		DBG_LEAVE(("STATUS_UNSUCCESSFUL %x", Status));
		return Status;
	}

	MySubKeyInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, size);
	if(MySubKeyInfo == NULL) {
		DBG_LEAVE(("STATUS_INSUFFICIENT_RESOURCES"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	Status = ZwEnumerateKey  (key,Num_SubKey,KeyBasicInformation,MySubKeyInfo,size,&size);
	if(! NT_SUCCESS(Status)) 
	{
		ExFreePool(MySubKeyInfo);
		DBG_LEAVE(("STATUS_UNSUCCESSFUL %x", Status));
		return Status;
	}
	if (bufsize < MySubKeyInfo->NameLength)
	{
		ExFreePool(MySubKeyInfo);
		DBG_LEAVE(("STATUS_INSUFFICIENT_RESOURCES"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	RtlZeroMemory(buf, bufsize);
	RtlCopyMemory(buf,MySubKeyInfo->Name,MySubKeyInfo->NameLength);

	//DBG_LEAVE(("SubKey %d %ws",Num_SubKey,buf));

	return STATUS_SUCCESS;
}

NTSTATUS RBC9_Get_Value_Info(HANDLE key,unsigned int Num_Value,WCHAR *buf,ULONG bufsize,ULONG * Type)
{

	NTSTATUS				Status;
	ULONG					size;
	PKEY_VALUE_BASIC_INFORMATION	MyValueInfo;

	//	DBG_ENTER((""));

	Status = ZwEnumerateValueKey  (key,Num_Value,KeyValueBasicInformation,NULL,0,&size);
	if(! NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 
	{
		DBG_LEAVE(("STATUS_UNSUCCESSFUL %x", Status));
		return Status;
	}

	MyValueInfo = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, size);
	if(MyValueInfo == NULL) {
		DBG_LEAVE(("STATUS_INSUFFICIENT_RESOURCES"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	Status = ZwEnumerateValueKey  (key,Num_Value,KeyValueBasicInformation,MyValueInfo,size,&size);
	if(! NT_SUCCESS(Status)) 
	{
		ExFreePool(MyValueInfo);
		DBG_LEAVE(("STATUS_UNSUCCESSFUL %x", Status));
		return Status;
	}
	if (bufsize < MyValueInfo->NameLength)
	{
		ExFreePool(MyValueInfo);
		DBG_LEAVE(("STATUS_INSUFFICIENT_RESOURCES"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	RtlZeroMemory(buf, bufsize);
	RtlCopyMemory(buf,MyValueInfo->Name,MyValueInfo->NameLength);

	if (Type != NULL)
	{
		*Type = MyValueInfo->Type;
	}

	//DBG_LEAVE(("MyValueInfo %d %ws",Num_Value,buf));

	return STATUS_SUCCESS;
}

NTSTATUS RBC9_Set_Data(HANDLE key, IN PWSTR name,IN ULONG Type , IN PVOID  Data,IN ULONG  DataSize)
{
	NTSTATUS						Status;
	UNICODE_STRING					uname;

	DBG_ENTER(("\"%ws", name));

	RtlInitUnicodeString(&uname, name);

	Status = ZwSetValueKey(key,&uname,0,Type,Data,DataSize);
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("%x", Status));
		return Status;
	}
	
	DBG_LEAVE(("STATUS_SUCCESS"));
	return Status;

}


NTSTATUS RBC9_Set_DWORD(HANDLE key , IN PWSTR name, IN LONG val)
{
	NTSTATUS						Status;

	// DBG_ENTER(("\"%ws\" %p, %u", name, *val, def_val));

	Status = RBC9_Set_Data(key, name,REG_DWORD, &val, sizeof(LONG));
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("%x", Status));
		return Status;
	}

	// DBG_LEAVE(("STATUS_SUCCESS: %u", *val));
	return STATUS_SUCCESS;
}

NTSTATUS RBC9_Set_BINARY(HANDLE key , IN PWSTR name, IN PVOID  Data,IN ULONG  DataSize)
{
	NTSTATUS						Status;

	// DBG_ENTER(("\"%ws\" %p, %u", name, *val, def_val));

	Status = RBC9_Set_Data(key, name,REG_BINARY, Data, DataSize);
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("%x", Status));
		return Status;
	}

	// DBG_LEAVE(("STATUS_SUCCESS: %u", *val));
	return STATUS_SUCCESS;
}



NTSTATUS RBC9_Get_Data(HANDLE key, IN PWSTR name, OUT PKEY_VALUE_PARTIAL_INFORMATION *val)
{
	UNICODE_STRING					uname;
	PKEY_VALUE_PARTIAL_INFORMATION	val_info;
	ULONG							size;
	NTSTATUS						Status;

	//   DBG_ENTER(("\"%ws %p", name, val));

	RtlInitUnicodeString(&uname, name);


	/* query size of data */
	Status = ZwQueryValueKey(key, &uname,
		KeyValuePartialInformation, NULL, 0,
		&size);
	if(! NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) {
		*val = NULL;
		DBG_LEAVE(("%x", Status));
		return Status;
	}

	/* allocate for query */
	val_info = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, size);
	if(val_info == NULL) {
		*val = NULL;
		DBG_LEAVE(("STATUS_INSUFFICIENT_RESOURCES"));
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	/* read data */
	Status = ZwQueryValueKey(key, &uname,
		KeyValuePartialInformation, val_info, size,
		&size);


	if(! NT_SUCCESS(Status)) {
		ExFreePool(val_info);
		*val = NULL;
		DBG_LEAVE(("%x", Status));
		return Status;
	}

	*val = val_info;
	//  DBG_LEAVE(("STATUS_SUCCESS"));
	return STATUS_SUCCESS;
}

NTSTATUS RBC9_Get_DWORD(HANDLE key , IN PWSTR name, OUT PLONG val, IN ULONG def_val)
{
	PKEY_VALUE_PARTIAL_INFORMATION	val_info;
	NTSTATUS						Status;

	//DBG_ENTER(("\"%ws\" %p, %u", name, *val, def_val));

	Status = RBC9_Get_Data(key, name, &val_info);
	if(! NT_SUCCESS(Status)) {
		*val = def_val;
		DBG_LEAVE(("%x, %u", Status, *val));
		return Status;
	}

	if(val_info->Type != REG_DWORD || val_info->DataLength != sizeof(LONG)) {
		ExFreePool(val_info);
		*val = def_val;
		DBG_LEAVE(("STATUS_UNSUCCESSFUL, %u", *val));
		return STATUS_UNSUCCESSFUL;
	}

	*val = *((LONG *)val_info->Data);

	ExFreePool(val_info);

	// DBG_LEAVE(("STATUS_SUCCESS: %u", *val));
	return STATUS_SUCCESS;
}


NTSTATUS RBC9_Get_STRING(HANDLE key , IN PWSTR name, OUT PWCHAR val, IN ULONG size)
{
	PKEY_VALUE_PARTIAL_INFORMATION	val_info;
	NTSTATUS						Status;

	//  DBG_ENTER(("%ws", name));

	RtlZeroMemory(val,size);

	Status = RBC9_Get_Data(key, name, &val_info);
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("Error Get Data %x", Status));
		return Status;
	}

	if(val_info->Type != REG_SZ)
	{
		ExFreePool(val_info);
		DBG_LEAVE(("STATUS_UNSUCCESSFUL"));
		return STATUS_UNSUCCESSFUL;
	}
	RtlCopyMemory(val, val_info->Data, (val_info->DataLength <(size-2) ) ? val_info->DataLength : (size-2));

	//	DBG_OUT(("Lentgh %d",val_info->DataLength));
	ExFreePool(val_info);

	//   DBG_LEAVE(("STATUS_SUCCESS"));
	return STATUS_SUCCESS;
}

NTSTATUS RBC9_Get_BINARY(HANDLE key , IN PWSTR name, OUT PVOID val, IN ULONG size)
{
	PKEY_VALUE_PARTIAL_INFORMATION	val_info;
	NTSTATUS						Status;

	//  DBG_ENTER(("%ws", name));

	RtlZeroMemory(val,size);

	Status = RBC9_Get_Data(key, name, &val_info);
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("Error Get Data %x", Status));
		return Status;
	}

	if(val_info->Type != REG_BINARY)
	{
		ExFreePool(val_info);
		DBG_LEAVE(("STATUS_UNSUCCESSFUL"));
		return STATUS_UNSUCCESSFUL;
	}
	RtlCopyMemory(val, val_info->Data, (val_info->DataLength <size ) ? val_info->DataLength : size);

	//DBG_OUT(("Lentgh %d",val_info->DataLength));
	ExFreePool(val_info);

	//   DBG_LEAVE(("STATUS_SUCCESS"));
	return STATUS_SUCCESS;
}


