#ifndef COMMON_H
#define COMMON_H

#ifdef VMP_GNU
#define VMP_IMPORT 
#else
#define VMP_IMPORT __declspec(dllimport)
#ifdef WIN_DRIVER
#ifdef _WIN64
	#pragma comment(lib, "../bin/64/Driver/VMProtectDDK64.lib")
#else
	#pragma comment(lib, "../bin/32/Driver/VMProtectDDK32.lib")
#endif // _WIN64
#else
#ifdef _WIN64
#ifdef NDEBUG
	#pragma comment(lib, "../bin/64/Release/VMProtectSDK64.lib")
#else
	#pragma comment(lib, "../bin/64/Debug/VMProtectSDK64.lib")
#endif
#else
#ifdef NDEBUG
	#pragma comment(lib, "../bin/32/Release/VMProtectSDK32.lib")
#else
	#pragma comment(lib, "../bin/32/Debug/VMProtectSDK32.lib")
#endif
#endif // _WIN64
#endif // WIN_DRIVER
#endif // VMP_GNU

#include "../sdk/sdk.h"

const size_t NOT_ID = (size_t)-1;

enum {
	MESSAGE_DEBUGGER_FOUND,
	MESSAGE_VIRTUAL_MACHINE_FOUND,
	MESSAGE_FILE_CORRUPTED,
	MESSAGE_SERIAL_NUMBER_REQUIRED,
	MESSAGE_HWID_MISMATCHED,
	MESSAGE_COUNT
};

#ifdef VMP_GNU
#define VMP_STR(s) s
#else
#define VMP_STR(s) L##s
#endif

#define MESSAGE_DEBUGGER_FOUND_STR VMP_STR("A debugger has been found running in your system.\nPlease, unload it from memory and restart your program.")
#define MESSAGE_VIRTUAL_MACHINE_FOUND_STR VMP_STR("Sorry, this application cannot run under a Virtual Machine.")
#define MESSAGE_FILE_CORRUPTED_STR VMP_STR("File corrupted! This program has been manipulated and maybe\nit's infected by a Virus or cracked. This file won't work anymore.")
#define MESSAGE_SERIAL_NUMBER_REQUIRED_STR VMP_STR("This code requires valid serial number to run.\nProgram will be terminated.")
#define MESSAGE_HWID_MISMATCHED_STR VMP_STR("This application cannot be executed on this computer.")
#define MESSAGE_UNREGISTERED_VERSION_STR VMP_STR("This application is protected with unregistered version of VMProtect and cannot be executed on this computer.")

enum {
	VAR_IS_PATCH_DETECTED,
	VAR_IS_DEBUGGER_DETECTED,
	VAR_LOADER_CRC_INFO,
	VAR_LOADER_CRC_INFO_SIZE,
	VAR_LOADER_CRC_INFO_HASH,
	VAR_SESSION_KEY,
	VAR_DRIVER_UNLOAD,
	VAR_CRC_IMAGE_SIZE,
	VAR_LOADER_STATUS,
	VAR_SERVER_DATE,
	VAR_OS_BUILD_NUMBER,
	VAR_CPU_COUNT,
	VAR_CPU_HASH,
	VAR_COUNT = VAR_CPU_HASH + 32
};

enum {
	FACE_MASK = 0xFACE0000U,

	FACE_RC5_P,
	FACE_RC5_Q,

	FACE_STRING_INFO,
	FACE_RESOURCE_INFO,
	FACE_STORAGE_INFO,
	FACE_REGISTRY_INFO,
	FACE_LICENSE_INFO,
	FACE_LICENSE_INFO_SIZE,
	FACE_KEY_INFO,
	FACE_RUNTIME_ENTRY,
	FACE_CRC_INFO_SALT,
	FACE_CRC_TABLE_ENTRY,
	FACE_CRC_TABLE_SIZE,
	FACE_CRC_TABLE_HASH,
	FACE_TRIAL_HWID,
	FACE_TRIAL_HWID_SIZE,
	FACE_CORE_OPTIONS,
	FACE_IMAGE_BASE,
	FACE_FILE_BASE,

	FACE_NTOSKRNL_NAME,
	FACE_HAL_NAME,
	FACE_USER32_NAME,
	FACE_MESSAGE_BOX_NAME,
	FACE_KERNEL32_NAME,
	FACE_CREATE_FILE_NAME,
	FACE_CLOSE_HANDLE_NAME,
	FACE_INITIALIZATION_ERROR,
	FACE_PROC_NOT_FOUND,
	FACE_ORDINAL_NOT_FOUND,
	FACE_STRING_DECRYPT_KEY,
	FACE_DRIVER_FORMAT_VALUE,
	FACE_FILE_CORRUPTED,
	FACE_LOADER_OPTIONS,
	FACE_LOADER_DATA,
	FACE_DEBUGGER_FOUND,
	FACE_NT_SET_INFORMATION_PROCESS_NAME,
	FACE_NT_RAISE_HARD_ERROR_NAME,
	FACE_IS_WOW64_PROCESS_NAME,
	FACE_WINE_GET_VERSION_NAME,
	FACE_MACOSX_FORMAT_VALUE,
	FACE_GNU_PTRACE,
	FACE_UNREGISTERED_VERSION,
	FACE_WTSAPI32_NAME,
	FACE_WTS_SEND_MESSAGE_NAME,
	FACE_NTDLL_NAME,
	FACE_NT_QUERY_INFORMATION_NAME,
	FACE_NT_SET_INFORMATION_THREAD_NAME,
	FACE_SICE_NAME,
	FACE_SIWVID_NAME,
	FACE_NTICE_NAME,
	FACE_ICEEXT_NAME,
	FACE_SYSER_NAME,
	FACE_VIRTUAL_MACHINE_FOUND,
	FACE_SBIEDLL_NAME,
	FACE_QUERY_VIRTUAL_MEMORY_NAME,
	FACE_ENUM_SYSTEM_FIRMWARE_NAME,
	FACE_GET_SYSTEM_FIRMWARE_NAME,
	FACE_NT_QUERY_INFORMATION_PROCESS_NAME,
	FACE_NT_VIRTUAL_PROTECT_NAME,
	FACE_NT_OPEN_FILE_NAME,
	FACE_NT_CREATE_SECTION_NAME,
	FACE_NT_OPEN_SECTION_NAME,
	FACE_NT_MAP_VIEW_OF_SECTION,
	FACE_NT_UNMAP_VIEW_OF_SECTION,
	FACE_NT_CLOSE,
	FACE_SYSCALL,
	FACE_NT_ALLOCATE_VIRTUAL_MEMORY_NAME,
	FACE_NT_FREE_VIRTUAL_MEMORY_NAME,

	FACE_PACKER_INFO = 0xFACE0100U,
	FACE_PACKER_INFO_SIZE,
	FACE_FILE_CRC_INFO,
	FACE_FILE_CRC_INFO_SIZE,
	FACE_LOADER_CRC_INFO,
	FACE_LOADER_CRC_INFO_SIZE,
	FACE_SECTION_INFO,
	FACE_SECTION_INFO_SIZE,
	FACE_FIXUP_INFO,
	FACE_FIXUP_INFO_SIZE,
	FACE_RELOCATION_INFO,
	FACE_RELOCATION_INFO_SIZE,
	FACE_IAT_INFO,
	FACE_IAT_INFO_SIZE,
	FACE_IMPORT_INFO,
	FACE_IMPORT_INFO_SIZE,
	FACE_INTERNAL_IMPORT_INFO,
	FACE_INTERNAL_IMPORT_INFO_SIZE,
	FACE_MEMORY_CRC_INFO,
	FACE_MEMORY_CRC_INFO_SIZE,
	FACE_DELAY_IMPORT_INFO,
	FACE_DELAY_IMPORT_INFO_SIZE,
	FACE_LOADER_CRC_INFO_HASH,
	FACE_MEMORY_CRC_INFO_HASH,
	FACE_TLS_INDEX_INFO,
	FACE_GNU_RELRO_INFO,
	FACE_NON_PAGED_POOL_NX,
	FACE_DEFAULT_MDL_PRIORITY,

	FACE_VAR = 0xFACE0200U,
	FACE_VAR_IS_PATCH_DETECTED = FACE_VAR | (VAR_IS_PATCH_DETECTED << 4),
	FACE_VAR_IS_DEBUGGER_DETECTED = FACE_VAR | (VAR_IS_DEBUGGER_DETECTED << 4),
	FACE_VAR_LOADER_CRC_INFO = FACE_VAR | (VAR_LOADER_CRC_INFO << 4),
	FACE_VAR_LOADER_CRC_INFO_SIZE = FACE_VAR | (VAR_LOADER_CRC_INFO_SIZE << 4),
	FACE_VAR_LOADER_CRC_INFO_HASH = FACE_VAR | (VAR_LOADER_CRC_INFO_HASH << 4),
	FACE_VAR_SESSION_KEY = FACE_VAR | (VAR_SESSION_KEY << 4),
	FACE_VAR_DRIVER_UNLOAD = FACE_VAR | (VAR_DRIVER_UNLOAD << 4),
	FACE_VAR_CRC_IMAGE_SIZE = FACE_VAR | (VAR_CRC_IMAGE_SIZE << 4),
	FACE_VAR_LOADER_STATUS = FACE_VAR | (VAR_LOADER_STATUS << 4),
	FACE_VAR_SERVER_DATE = FACE_VAR | (VAR_SERVER_DATE << 4),
	FACE_VAR_CPU_COUNT = FACE_VAR | (VAR_CPU_COUNT << 4),
	FACE_VAR_CPU_HASH = FACE_VAR | (VAR_CPU_HASH << 4),
	FACE_VAR_OS_BUILD_NUMBER = FACE_VAR | (VAR_OS_BUILD_NUMBER << 4),

	FACE_VAR_SALT = 0xFACE0300U,
	FACE_VAR_IS_PATCH_DETECTED_SALT = FACE_VAR_SALT | VAR_IS_PATCH_DETECTED,
	FACE_VAR_IS_DEBUGGER_DETECTED_SALT = FACE_VAR_SALT | VAR_IS_DEBUGGER_DETECTED,
	FACE_VAR_LOADER_CRC_INFO_SALT = FACE_VAR_SALT | VAR_LOADER_CRC_INFO,
	FACE_VAR_LOADER_CRC_INFO_SIZE_SALT = FACE_VAR_SALT | VAR_LOADER_CRC_INFO_SIZE,
	FACE_VAR_LOADER_CRC_INFO_HASH_SALT = FACE_VAR_SALT | VAR_LOADER_CRC_INFO_HASH,
	FACE_VAR_DRIVER_UNLOAD_SALT = FACE_VAR_SALT | VAR_DRIVER_UNLOAD,
	FACE_VAR_CRC_IMAGE_SIZE_SALT = FACE_VAR_SALT | VAR_CRC_IMAGE_SIZE,
	FACE_VAR_SERVER_DATE_SALT = FACE_VAR_SALT | VAR_SERVER_DATE,
	FACE_VAR_CPU_COUNT_SALT = FACE_VAR_SALT | VAR_CPU_COUNT,
	FACE_VAR_CPU_HASH_SALT = FACE_VAR_SALT | VAR_CPU_HASH,
	FACE_VAR_OS_BUILD_NUMBER_SALT = FACE_VAR_SALT | VAR_OS_BUILD_NUMBER,
};

enum {
	LOADER_OPTION_CHECK_PATCH = 0x1,
	LOADER_OPTION_CHECK_DEBUGGER = 0x2,
	LOADER_OPTION_CHECK_KERNEL_DEBUGGER = 0x4,
	LOADER_OPTION_EXIT_PROCESS = 0x8,
	LOADER_OPTION_CHECK_VIRTUAL_MACHINE = 0x10
};

enum {
	CORE_OPTION_MEMORY_PROTECTION = 0x1,
	CORE_OPTION_CHECK_DEBUGGER = 0x2
};

enum {
	FILE_LOAD = 0x1,
	FILE_REGISTER = 0x2,
	FILE_INSTALL = 0x4,
};

enum {
	FIELD_BUILD_DATE,
	FIELD_PUBLIC_EXP_OFFSET,
	FIELD_PUBLIC_EXP_SIZE,
	FIELD_MODULUS_OFFSET,
	FIELD_MODULUS_SIZE,
	FIELD_BLACKLIST_OFFSET,
	FIELD_BLACKLIST_SIZE,
	FIELD_ACTIVATION_URL_OFFSET,
	FIELD_ACTIVATION_URL_SIZE,
	FIELD_CRC_OFFSET,
	FIELD_COUNT
};

enum {
	WOW64_FLAG = 0x8000
};

#ifndef _CONSOLE // google test
#define FACE_TO_INDEX(i) ((uint32_t)(i)/sizeof(size_t))
#ifdef VMP_GNU
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warray-bounds"
#endif
#else
#define FACE_TO_INDEX(i) (((uint32_t)(i) & 0xff) >> 4)
#endif

struct GlobalData {
	bool is_patch_detected() { return ((v_[FACE_TO_INDEX(FACE_VAR_IS_PATCH_DETECTED)] ^ FACE_VAR_IS_PATCH_DETECTED_SALT) != 0); } //-V557
	bool is_debugger_detected() { return ((v_[FACE_TO_INDEX(FACE_VAR_IS_DEBUGGER_DETECTED)] ^ FACE_VAR_IS_DEBUGGER_DETECTED_SALT) != 0); } //-V557
	size_t loader_crc_info() { return (v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO)] ^ FACE_VAR_LOADER_CRC_INFO_SALT); } //-V557
	size_t loader_crc_size() { return (v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_SIZE)] ^ FACE_VAR_LOADER_CRC_INFO_SIZE_SALT); } //-V557
	size_t loader_crc_hash() { return (v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_HASH)] ^ FACE_VAR_LOADER_CRC_INFO_HASH_SALT); } //-V557
	size_t cpu_hash(size_t index) { return (v_[FACE_TO_INDEX(FACE_VAR_CPU_HASH) + index] ^ FACE_VAR_CPU_HASH_SALT); }
	size_t cpu_count() { return (v_[FACE_TO_INDEX(FACE_VAR_CPU_COUNT)] ^ FACE_VAR_CPU_COUNT_SALT); } //-V557
	size_t session_key() { return (v_[FACE_TO_INDEX(FACE_VAR_SESSION_KEY)]); } //-V557
	size_t driver_unload() { return (v_[FACE_TO_INDEX(FACE_VAR_DRIVER_UNLOAD)] ^ FACE_VAR_DRIVER_UNLOAD_SALT); } //-V557
	size_t crc_image_size() { return (v_[FACE_TO_INDEX(FACE_VAR_CRC_IMAGE_SIZE)] ^ FACE_VAR_CRC_IMAGE_SIZE_SALT); } //-V557
	uint32_t loader_status() { return static_cast<uint32_t>(v_[FACE_TO_INDEX(FACE_VAR_LOADER_STATUS)]); } //-V557
	uint32_t server_date() { return static_cast<uint32_t>(v_[FACE_TO_INDEX(FACE_VAR_SERVER_DATE)] ^ FACE_VAR_SERVER_DATE_SALT); } //-V557
	uint32_t os_build_number() { return static_cast<uint32_t>(v_[FACE_TO_INDEX(FACE_VAR_OS_BUILD_NUMBER)] ^ FACE_VAR_OS_BUILD_NUMBER_SALT); } //-V557

	void set_is_patch_detected(bool value) { v_[FACE_TO_INDEX(FACE_VAR_IS_PATCH_DETECTED)] = static_cast<size_t>(value) ^ FACE_VAR_IS_PATCH_DETECTED_SALT; } //-V557
	void set_is_debugger_detected(bool value) { v_[FACE_TO_INDEX(FACE_VAR_IS_DEBUGGER_DETECTED)] = static_cast<size_t>(value) ^ FACE_VAR_IS_DEBUGGER_DETECTED_SALT; } //-V557
	void set_loader_crc_info(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO)] = value ^ FACE_VAR_LOADER_CRC_INFO_SALT; } //-V557
	void set_loader_crc_size(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_SIZE)] = value ^ FACE_VAR_LOADER_CRC_INFO_SIZE_SALT; } //-V557
	void set_loader_crc_hash(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_CRC_INFO_HASH)] = value ^ FACE_VAR_LOADER_CRC_INFO_HASH_SALT; } //-V557
	void set_cpu_hash(size_t index, size_t value) { v_[FACE_TO_INDEX(FACE_VAR_CPU_HASH) + index] = value ^ FACE_VAR_CPU_HASH_SALT; }
	void set_cpu_count(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_CPU_COUNT)] = value ^ FACE_VAR_CPU_COUNT_SALT; } //-V557
	void set_session_key(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_SESSION_KEY)] = value; } //-V557
	void set_driver_unload(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_DRIVER_UNLOAD)] = value ^ FACE_VAR_DRIVER_UNLOAD_SALT; } //-V557
	void set_crc_image_size(size_t value) { v_[FACE_TO_INDEX(FACE_VAR_CRC_IMAGE_SIZE)] = value ^ FACE_VAR_CRC_IMAGE_SIZE_SALT; } //-V557
	void set_loader_status(uint32_t value) { v_[FACE_TO_INDEX(FACE_VAR_LOADER_STATUS)] = value; } //-V557
	void set_server_date(uint32_t value) { v_[FACE_TO_INDEX(FACE_VAR_SERVER_DATE)] = value ^ FACE_VAR_SERVER_DATE_SALT; } //-V557
	void set_os_build_number(uint32_t value) { v_[FACE_TO_INDEX(FACE_VAR_OS_BUILD_NUMBER)] = value ^ FACE_VAR_OS_BUILD_NUMBER_SALT; } //-V557
private:
	size_t v_[VAR_COUNT];
};

#ifndef _CONSOLE
#ifdef VMP_GNU
#pragma clang diagnostic pop
#endif
#endif

#endif