#ifndef __NATIVE_CODE_H
#define __NATIVE_CODE_H

#include "Windas.h"
#include "XedWrap.h"
#include "Code.h"

struct _NATIVE_CODE_BLOCK;
struct _NATIVE_CODE_LINK;

typedef BOOL(*FN_INST_ASM_OP)(_NATIVE_CODE_LINK* Link, PUCHAR ToMutate, PVOID Context);

typedef struct _NATIVE_CODE_LINK
{
	_NATIVE_CODE_LINK*			Next;
	_NATIVE_CODE_LINK*			Prev;
	_NATIVE_CODE_BLOCK*			Block;
	ULONG						Flags;
	ULONG						Label;
	PUCHAR						RawData;
	ULONG						RawDataSize;
	XED_DECODED_INST			XedInstruction;
	STDVECTOR<STDPAIR<FN_INST_ASM_OP, PVOID>>	AsmOperations;
	_NATIVE_CODE_LINK();
	_NATIVE_CODE_LINK(ULONG LabelId, _NATIVE_CODE_BLOCK* B);
	_NATIVE_CODE_LINK(ULONG F, PVOID Rd, ULONG Rds, BOOL Decode = FALSE);
	~_NATIVE_CODE_LINK();
}NATIVE_CODE_LINK, *PNATIVE_CODE_LINK;

typedef struct _NATIVE_CODE_BLOCK
{
	PNATIVE_CODE_LINK	Start;
	PNATIVE_CODE_LINK	End;
	STDVECTOR<ULONG>	LabelIds;
	_NATIVE_CODE_BLOCK();
}NATIVE_CODE_BLOCK, *PNATIVE_CODE_BLOCK;

VOID NcAppendToBlock(PNATIVE_CODE_BLOCK Block, PNATIVE_CODE_LINK Link);

VOID NcPrependToBlock(PNATIVE_CODE_BLOCK Block, PNATIVE_CODE_LINK Link);

VOID NcInsertLinkAfter(PNATIVE_CODE_LINK Link1, PNATIVE_CODE_LINK Link2);

VOID NcInsertLinkBefore(PNATIVE_CODE_LINK Link1, PNATIVE_CODE_LINK Link2);

VOID NcUnlink(PNATIVE_CODE_LINK Link);

ULONG NcCountInstructions(PNATIVE_CODE_BLOCK Block, BOOL CountCombinedAsOne = FALSE);

ULONG NcCalcBlockSizeInBytes(PNATIVE_CODE_BLOCK Block);

VOID NcChangeLabelId(PNATIVE_CODE_BLOCK Block1, ULONG Original, ULONG New);

ULONG NcGenUnusedLabelId(PNATIVE_CODE_BLOCK Block);

VOID NcFixLabelsForBlocks(PNATIVE_CODE_BLOCK Block1, PNATIVE_CODE_BLOCK Block2);

BOOL NcInsertBlockAfter(PNATIVE_CODE_LINK Link, PNATIVE_CODE_BLOCK Block, BOOL FixLabels = TRUE);

BOOL NcInsertBlockBefore(PNATIVE_CODE_LINK Link, PNATIVE_CODE_BLOCK Block, BOOL FixLabels = TRUE);

BOOL NcCreateLabels(PNATIVE_CODE_BLOCK Block);

PNATIVE_CODE_LINK NcValidateJmp(PNATIVE_CODE_LINK Link, INT32 Delta);

PNATIVE_CODE_LINK NcDeepCopyLink(PNATIVE_CODE_LINK Link);

BOOL NcDeepCopyPartialBlock(PNATIVE_CODE_LINK Start, PNATIVE_CODE_LINK End, PNATIVE_CODE_BLOCK Block);

BOOL NcDeepCopyBlock(PNATIVE_CODE_BLOCK Block, PNATIVE_CODE_BLOCK BlockCopy);

BOOL NcGetDeltaToLabel(PNATIVE_CODE_LINK Link, PINT32 DeltaOut);

BOOL NcFixRelJmps(PNATIVE_CODE_BLOCK Block);

BOOL NcDisassemble(PNATIVE_CODE_BLOCK Block, PVOID Buffer, ULONG BufferSize);

PVOID NcAssemble(PNATIVE_CODE_BLOCK Block, PULONG OutSize);

PVOID NcAssembleEx(PNATIVE_CODE_BLOCK Block, PULONG OutSize, BOOL ChooseRandomDuplicateLabel);

VOID NcDeleteBlock(PNATIVE_CODE_BLOCK Block);

VOID NcDebugPrint(PNATIVE_CODE_BLOCK Block);

VOID NcPrintBlockCode(PNATIVE_CODE_BLOCK Block);

#endif