#ifndef LIEF_PE_STRUCTURES_H_
#define LIEF_PE_STRUCTURES_H_
#include <type_traits>
#include <map>

#include "LIEF/types.hpp"

#include "LIEF/PE/enums.hpp"

namespace LIEF {

//! Namespace related to the LIEF's PE module
//!
//! Some parts from llvm/Support/COFF.h
namespace PE {

//! Sizes in bytes of various things in the COFF format.
namespace STRUCT_SIZES {
  enum {
    Header16Size                  = 20,
    Header32Size                  = 56,
    NameSize                      = 8,
    Symbol16Size                  = 18,
    Symbol32Size                  = 20,
    SectionSize                   = 40,
    RelocationSize                = 10,
    BaseRelocationBlockSize       = 8,
    ImportDirectoryTableEntrySize = 20,
    ResourceDirectoryTableSize    = 16,
    ResourceDirectoryEntriesSize  = 8,
    ResourceDataEntrySize         = 16
  };
}



//! The maximum number of sections that a COFF object can have (inclusive).
static const int32_t MaxNumberOfSections16 = 65279;

//! The PE signature bytes that follows the DOS stub header.
static const char PE_Magic[] = { 'P', 'E', '\0', '\0' };

static const char Rich_Magic[] = {'R', 'i', 'c', 'h'};
static const char DanS_Magic[] = {'D', 'a', 'n', 'S'};

static const uint32_t DanS_Magic_number = 0x536E6144;

static const char BigObjMagic[] = {
  '\xc7', '\xa1', '\xba', '\xd1', '\xee', '\xba', '\xa9', '\x4b',
  '\xaf', '\x20', '\xfa', '\xf6', '\x6a', '\xa4', '\xdc', '\xb8',
};

static const uint8_t DEFAULT_NUMBER_DATA_DIRECTORIES = 15;

#pragma pack(push,1)
struct pe_header {
  char     signature[sizeof(PE_Magic)];
  uint16_t Machine;
  uint16_t NumberOfSections;
  uint32_t TimeDateStamp;
  uint32_t PointerToSymbolTable;
  uint32_t NumberOfSymbols;
  uint16_t SizeOfOptionalHeader;
  uint16_t Characteristics;
};


struct pe_relocation {
  uint32_t VirtualAddress;
  uint32_t SymbolTableIndex;
  uint16_t Type;
};

struct pe_base_relocation_block {
  uint32_t PageRVA;
  uint32_t BlockSize;
};


struct pe_symbol {
  union {
    char ShortName[8];
    struct
		{
	    uint32_t Zeroes;
			uint32_t Offset;
    } Name;
  } Name;
  uint32_t Value;
  int16_t  SectionNumber;
  uint16_t Type;
  uint8_t  StorageClass;
  uint8_t  NumberOfAuxSymbols;
};


struct pe_section {
  char     Name[8];
  uint32_t VirtualSize;
  uint32_t VirtualAddress;
  uint32_t SizeOfRawData;
  uint32_t PointerToRawData;
  uint32_t PointerToRelocations;
  uint32_t PointerToLineNumbers;
  uint16_t NumberOfRelocations;
  uint16_t NumberOfLineNumbers;
  uint32_t Characteristics;
};

struct AuxiliaryFunctionDefinition {
  uint32_t TagIndex;
  uint32_t TotalSize;
  uint32_t PointerToLinenumber;
  uint32_t PointerToNextFunction;
  char     unused[2];
};

struct AuxiliarybfAndefSymbol {
  uint8_t  unused1[4];
  uint16_t Linenumber;
  uint8_t  unused2[6];
  uint32_t PointerToNextFunction;
  uint8_t  unused3[2];
};

struct AuxiliaryWeakExternal {
  uint32_t TagIndex;
  uint32_t Characteristics;
  uint8_t  unused[10];
};


struct AuxiliarySectionDefinition {
  uint32_t Length;
  uint16_t NumberOfRelocations;
  uint16_t NumberOfLinenumbers;
  uint32_t CheckSum;
  uint32_t Number;
  uint8_t  Selection;
  char     unused;
};

struct AuxiliaryCLRToken {
  uint8_t  AuxType;
  uint8_t  unused1;
  uint32_t SymbolTableIndex;
  char     unused2[12];
};

union Auxiliary {
  AuxiliaryFunctionDefinition FunctionDefinition;
  AuxiliarybfAndefSymbol      bfAndefSymbol;
  AuxiliaryWeakExternal       WeakExternal;
  AuxiliarySectionDefinition  SectionDefinition;
};


/// @brief The Import Directory Table.
///
/// There is a single array of these and one entry per imported DLL.
struct pe_import {
  uint32_t ImportLookupTableRVA;
  uint32_t TimeDateStamp;
  uint32_t ForwarderChain;
  uint32_t NameRVA;
  uint32_t ImportAddressTableRVA;
};


struct ImportLookupTableEntry32 {
  uint32_t data;
};

struct ImportLookupTableEntry64 {
  uint64_t data;
};


struct pe32_tls {
  uint32_t RawDataStartVA;
  uint32_t RawDataEndVA;
  uint32_t AddressOfIndex;
  uint32_t AddressOfCallback;
  uint32_t SizeOfZeroFill;
  uint32_t Characteristics;
};


struct pe64_tls {
  uint64_t RawDataStartVA;
  uint64_t RawDataEndVA;
  uint64_t AddressOfIndex;
  uint64_t AddressOfCallback;
  uint32_t SizeOfZeroFill;
  uint32_t Characteristics;
};


/// @brief The DOS compatible header at the front of all PEs.
struct pe_dos_header {
  uint16_t Magic;
  uint16_t UsedBytesInTheLastPage;
  uint16_t FileSizeInPages;
  uint16_t NumberOfRelocationItems;
  uint16_t HeaderSizeInParagraphs;
  uint16_t MinimumExtraParagraphs;
  uint16_t MaximumExtraParagraphs;
  uint16_t InitialRelativeSS;
  uint16_t InitialSP;
  uint16_t Checksum;
  uint16_t InitialIP;
  uint16_t InitialRelativeCS;
  uint16_t AddressOfRelocationTable;
  uint16_t OverlayNumber;
  uint16_t Reserved[4];
  uint16_t OEMid;
  uint16_t OEMinfo;
  uint16_t Reserved2[10];
  uint32_t AddressOfNewExeHeader;
};

struct pe64_optional_header {
  uint16_t Magic;
  uint8_t  MajorLinkerVersion;
  uint8_t  MinorLinkerVersion;
  uint32_t SizeOfCode;
  uint32_t SizeOfInitializedData;
  uint32_t SizeOfUninitializedData;
  uint32_t AddressOfEntryPoint; // RVA
  uint32_t BaseOfCode; // RVA
  //uint32_t BaseOfData; // RVA
  uint64_t ImageBase;
  uint32_t SectionAlignment;
  uint32_t FileAlignment;
  uint16_t MajorOperatingSystemVersion;
  uint16_t MinorOperatingSystemVersion;
  uint16_t MajorImageVersion;
  uint16_t MinorImageVersion;
  uint16_t MajorSubsystemVersion;
  uint16_t MinorSubsystemVersion;
  uint32_t Win32VersionValue;
  uint32_t SizeOfImage;
  uint32_t SizeOfHeaders;
  uint32_t CheckSum;
  uint16_t Subsystem;
  uint16_t DLLCharacteristics;
  uint64_t SizeOfStackReserve;
  uint64_t SizeOfStackCommit;
  uint64_t SizeOfHeapReserve;
  uint64_t SizeOfHeapCommit;
  uint32_t LoaderFlags;
  uint32_t NumberOfRvaAndSize;
};


struct pe32_optional_header {
  uint16_t Magic;
  uint8_t  MajorLinkerVersion;
  uint8_t  MinorLinkerVersion;
  uint32_t SizeOfCode;
  uint32_t SizeOfInitializedData;
  uint32_t SizeOfUninitializedData;
  uint32_t AddressOfEntryPoint; // RVA
  uint32_t BaseOfCode; // RVA
  uint32_t BaseOfData; // RVA
  uint32_t ImageBase;
  uint32_t SectionAlignment;
  uint32_t FileAlignment;
  uint16_t MajorOperatingSystemVersion;
  uint16_t MinorOperatingSystemVersion;
  uint16_t MajorImageVersion;
  uint16_t MinorImageVersion;
  uint16_t MajorSubsystemVersion;
  uint16_t MinorSubsystemVersion;
  uint32_t Win32VersionValue;
  uint32_t SizeOfImage;
  uint32_t SizeOfHeaders;
  uint32_t CheckSum;
  uint16_t Subsystem;
  uint16_t DLLCharacteristics;
  uint32_t SizeOfStackReserve;
  uint32_t SizeOfStackCommit;
  uint32_t SizeOfHeapReserve;
  uint32_t SizeOfHeapCommit;
  uint32_t LoaderFlags;
  uint32_t NumberOfRvaAndSize;
};


struct pe_data_directory {
  uint32_t RelativeVirtualAddress;
  uint32_t Size;
};


struct pe_debug {
  uint32_t Characteristics;
  uint32_t TimeDateStamp;
  uint16_t MajorVersion;
  uint16_t MinorVersion;
  uint32_t Type;
  uint32_t SizeOfData;
  uint32_t AddressOfRawData;
  uint32_t PointerToRawData;
};


struct pe_pdb_70 {
  uint32_t cv_signature;
  uint8_t  signature[16];
  uint32_t age;
  char*    filename;
};

struct pe_pdb_20 {
  uint32_t cv_signature;
  uint32_t offset;
  uint32_t signature;
  uint32_t age;
  char*    filename;
};


struct pe_resource_directory_table {
  uint32_t Characteristics;
  uint32_t TimeDateStamp;
  uint16_t MajorVersion;
  uint16_t MinorVersion;
  uint16_t NumberOfNameEntries;
  uint16_t NumberOfIDEntries;
};

struct pe_resource_directory_entries {
  union {
    uint32_t NameRVA;
    uint32_t IntegerID;
  } NameID;
  uint32_t RVA;
};

struct pe_resource_data_entry {
  uint32_t DataRVA;
  uint32_t Size;
  uint32_t Codepage;
  uint32_t Reserved;
};

struct pe_resource_string {
  int16_t Length;
  uint16_t Name[1];
};


//
// Export structures
//
struct pe_export_directory_table {
  uint32_t ExportFlags;           ///< Reserverd must be 0
  uint32_t Timestamp;             ///< The time and date that the export data was created
  uint16_t MajorVersion;          ///< The Major version number
  uint16_t MinorVersion;          ///< The Minor version number
  uint32_t NameRVA;               ///< The address of the ASCII DLL's name (RVA)
  uint32_t OrdinalBase;           ///< The starting ordinal number for exports. (Usually 1)
  uint32_t AddressTableEntries;   ///< Number of entries in the export address table
  uint32_t NumberOfNamePointers;  ///< Number of entries in the name pointer table
  uint32_t ExportAddressTableRVA; ///< Address of the export address table (RVA)
  uint32_t NamePointerRVA;        ///< Address of the name pointer table (RVA)
  uint32_t OrdinalTableRVA;       ///< Address of the ordinal table (RVA)
};


struct pe_resource_fixed_file_info {
  uint32_t signature;          // e.g.  0xfeef04bd
  uint32_t struct_version;      // e.g.  0x00000042 = "0.42"
  uint32_t file_version_MS;    // e.g.  0x00030075 = "3.75"
  uint32_t file_version_LS;    // e.g.  0x00000031 = "0.31"
  uint32_t product_version_MS; // e.g.  0x00030010 = "3.10"
  uint32_t product_version_LS; // e.g.  0x00000031 = "0.31"
  uint32_t file_flags_mask;    // = 0x3F for version "0.42"
  uint32_t file_flags;         // e.g.  VFF_DEBUG | VFF_PRERELEASE
  uint32_t file_OS;            // e.g.  VOS_DOS_WINDOWS16
  uint32_t file_type;          // e.g.  VFT_DRIVER
  uint32_t file_subtype;       // e.g.  VFT2_DRV_KEYBOARD
  uint32_t file_date_MS;       // e.g.  0
  uint32_t file_date_LS;       // e.g.  0
};


struct pe_resource_version_info {
  uint16_t length;
  uint16_t sizeof_value;
  uint16_t type;
  char16_t key[16];
  // uint16_t padding;
  //
  // uint16_t padding;
  // uint16_t children
};

//! @brief Resource icons directory structure
//! Based on https://msdn.microsoft.com/en-us/library/ff468901(v=vs.85).aspx
//!
//! This is the begining of the RESOURCE_TYPES::GROUP_ICON content
struct pe_resource_icon_dir {
  uint16_t reserved; ///< Reserved
  uint16_t type;     ///< Resource type (1 for icons)
  uint16_t count;    ///< Number of icons
};


//! @brief Structure that follows pe_resource_icon_dir in a resource entry
struct pe_resource_icon_group {
	uint8_t width;        ///< Width, in pixels, of the image
	uint8_t height;       ///< Height, in pixels, of the image
	uint8_t color_count;  ///< Number of colors in image (0 if >=8bpp)
	uint8_t reserved;     ///< Reserved (must be 0)
	uint16_t planes;      ///< Color Planes
	uint16_t bit_count;   ///< Bits per pixel
	uint32_t size;        ///< Size of the image in bytes
	uint16_t ID;          ///< The associated ID
};

//! @brief Structure that follows pe_resource_icon_dir in a icon **file**
struct pe_icon_header {
	uint8_t width;        ///< Width, in pixels, of the image
	uint8_t height;       ///< Height, in pixels, of the image
	uint8_t color_count;  ///< Number of colors in image (0 if >=8bpp)
	uint8_t reserved;     ///< Reserved (must be 0)
	uint16_t planes;      ///< Color Planes
	uint16_t bit_count;   ///< Bits per pixel
	uint32_t size;        ///< Size of the image in bytes
	uint32_t offset;      ///< Offset to the pixels
};

//! @brief Extended dialog box template
struct pe_dialog_template_ext {
  uint16_t version;
  uint16_t signature;
  uint32_t help_id;
  uint32_t ext_style;
  uint32_t style;
  uint16_t nbof_items;
  int16_t x;
  int16_t y;
  int16_t cx;
  int16_t cy;
  // sz_Or_Ord menu;
  // sz_Or_Ord windowClass;
  // char16_t  title[titleLen];
  // uint16_t  pointsize;
  // uint16_t  weight;
  // uint8_t   italic;
  // uint8_t   charset;
  // char16_t  typeface[stringLen];
};

//! @brief Dialog box template
struct pe_dialog_template {
  uint32_t style;
  uint32_t ext_style;
  uint16_t nbof_items;
  int16_t x;
  int16_t y;
  int16_t cx;
  int16_t cy;
};


//! @brief Extended dialog box template item
struct pe_dialog_item_template_ext {
  uint32_t help_id;
  uint32_t ext_style;
  uint32_t style;
  int16_t x;
  int16_t y;
  int16_t cx;
  int16_t cy;
  uint32_t id;
  // sz_Or_Ord windowClass;
  // sz_Or_Ord title;
  // uint16_t extra_count;
};


//! @brief Dialog box template item
struct pe_dialog_item_template {
  uint32_t style;
  uint32_t ext_style;
  int16_t x;
  int16_t y;
  int16_t cx;
  int16_t cy;
  uint16_t id;
};

struct pe_code_integrity {
  uint16_t Flags;
  uint16_t Catalog;
  uint32_t CatalogOffset;
  uint32_t Reserved;
};






#pragma pack(pop)



static const HEADER_CHARACTERISTICS header_characteristics_array[] = {
  HEADER_CHARACTERISTICS::IMAGE_FILE_INVALID,
  HEADER_CHARACTERISTICS::IMAGE_FILE_RELOCS_STRIPPED,
  HEADER_CHARACTERISTICS::IMAGE_FILE_EXECUTABLE_IMAGE,
  HEADER_CHARACTERISTICS::IMAGE_FILE_LINE_NUMS_STRIPPED,
  HEADER_CHARACTERISTICS::IMAGE_FILE_LOCAL_SYMS_STRIPPED,
  HEADER_CHARACTERISTICS::IMAGE_FILE_AGGRESSIVE_WS_TRIM,
  HEADER_CHARACTERISTICS::IMAGE_FILE_LARGE_ADDRESS_AWARE,
  HEADER_CHARACTERISTICS::IMAGE_FILE_BYTES_REVERSED_LO,
  HEADER_CHARACTERISTICS::IMAGE_FILE_32BIT_MACHINE,
  HEADER_CHARACTERISTICS::IMAGE_FILE_DEBUG_STRIPPED,
  HEADER_CHARACTERISTICS::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,
  HEADER_CHARACTERISTICS::IMAGE_FILE_NET_RUN_FROM_SWAP,
  HEADER_CHARACTERISTICS::IMAGE_FILE_SYSTEM,
  HEADER_CHARACTERISTICS::IMAGE_FILE_DLL,
  HEADER_CHARACTERISTICS::IMAGE_FILE_UP_SYSTEM_ONLY,
  HEADER_CHARACTERISTICS::IMAGE_FILE_BYTES_REVERSED_HI
};


// Common section type
enum class PE_SECTION_TYPES : uint8_t {
  TEXT       = 0,
  TLS        = 1,
  IMPORT     = 2,
  DATA       = 3,
  BSS        = 4,
  RESOURCE   = 5,
  RELOCATION = 6,
  EXPORT     = 7,
  DEBUG      = 8,
  LOAD_CONFIG = 9,
  UNKNOWN     = 10
};


static const SECTION_CHARACTERISTICS section_characteristics_array[] = {
  SECTION_CHARACTERISTICS::IMAGE_SCN_TYPE_NO_PAD,
  SECTION_CHARACTERISTICS::IMAGE_SCN_CNT_CODE,
  SECTION_CHARACTERISTICS::IMAGE_SCN_CNT_INITIALIZED_DATA,
  SECTION_CHARACTERISTICS::IMAGE_SCN_CNT_UNINITIALIZED_DATA,
  SECTION_CHARACTERISTICS::IMAGE_SCN_LNK_OTHER,
  SECTION_CHARACTERISTICS::IMAGE_SCN_LNK_INFO,
  SECTION_CHARACTERISTICS::IMAGE_SCN_LNK_REMOVE,
  SECTION_CHARACTERISTICS::IMAGE_SCN_LNK_COMDAT,
  SECTION_CHARACTERISTICS::IMAGE_SCN_GPREL,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_PURGEABLE,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_16BIT,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_LOCKED,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_PRELOAD,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_1BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_2BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_4BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_8BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_16BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_32BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_64BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_128BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_256BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_512BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_1024BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_2048BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_4096BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_ALIGN_8192BYTES,
  SECTION_CHARACTERISTICS::IMAGE_SCN_LNK_NRELOC_OVFL,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_DISCARDABLE,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_NOT_CACHED,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_NOT_PAGED,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_SHARED,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_EXECUTE,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_READ,
  SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_WRITE,
};


enum class PE_TYPE : uint16_t {
    PE32      = 0x10b, ///< 32bits
    PE32_PLUS = 0x20b  ///< 64 bits
};



static const DLL_CHARACTERISTICS dll_characteristics_array[] = {
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_NX_COMPAT,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_NO_SEH,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_NO_BIND,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_APPCONTAINER,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_GUARD_CF,
  DLL_CHARACTERISTICS::IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE,
};


static const EXTENDED_WINDOW_STYLES extended_window_styles_array[] = {
  EXTENDED_WINDOW_STYLES::WS_EX_DLGMODALFRAME,
  EXTENDED_WINDOW_STYLES::WS_EX_NOPARENTNOTIFY,
  EXTENDED_WINDOW_STYLES::WS_EX_TOPMOST,
  EXTENDED_WINDOW_STYLES::WS_EX_ACCEPTFILES,
  EXTENDED_WINDOW_STYLES::WS_EX_TRANSPARENT,
  EXTENDED_WINDOW_STYLES::WS_EX_MDICHILD,
  EXTENDED_WINDOW_STYLES::WS_EX_TOOLWINDOW,
  EXTENDED_WINDOW_STYLES::WS_EX_WINDOWEDGE,
  EXTENDED_WINDOW_STYLES::WS_EX_CLIENTEDGE,
  EXTENDED_WINDOW_STYLES::WS_EX_CONTEXTHELP,
  EXTENDED_WINDOW_STYLES::WS_EX_RIGHT,
  EXTENDED_WINDOW_STYLES::WS_EX_LEFT,
  EXTENDED_WINDOW_STYLES::WS_EX_RTLREADING,
  EXTENDED_WINDOW_STYLES::WS_EX_LTRREADING,
  EXTENDED_WINDOW_STYLES::WS_EX_LEFTSCROLLBAR,
  EXTENDED_WINDOW_STYLES::WS_EX_RIGHTSCROLLBAR,
  EXTENDED_WINDOW_STYLES::WS_EX_CONTROLPARENT,
  EXTENDED_WINDOW_STYLES::WS_EX_STATICEDGE,
  EXTENDED_WINDOW_STYLES::WS_EX_APPWINDOW,
};


static const WINDOW_STYLES window_styles_array[] = {
  WINDOW_STYLES::WS_OVERLAPPED,
  WINDOW_STYLES::WS_POPUP,
  WINDOW_STYLES::WS_CHILD,
  WINDOW_STYLES::WS_MINIMIZE,
  WINDOW_STYLES::WS_VISIBLE,
  WINDOW_STYLES::WS_DISABLED,
  WINDOW_STYLES::WS_CLIPSIBLINGS,
  WINDOW_STYLES::WS_CLIPCHILDREN,
  WINDOW_STYLES::WS_MAXIMIZE,
  WINDOW_STYLES::WS_CAPTION,
  WINDOW_STYLES::WS_BORDER,
  WINDOW_STYLES::WS_DLGFRAME,
  WINDOW_STYLES::WS_VSCROLL,
  WINDOW_STYLES::WS_HSCROLL,
  WINDOW_STYLES::WS_SYSMENU,
  WINDOW_STYLES::WS_THICKFRAME,
  WINDOW_STYLES::WS_GROUP,
  WINDOW_STYLES::WS_TABSTOP,
  WINDOW_STYLES::WS_MINIMIZEBOX,
  WINDOW_STYLES::WS_MAXIMIZEBOX,
};


static const DIALOG_BOX_STYLES dialog_box_styles_array[] = {
  DIALOG_BOX_STYLES::DS_ABSALIGN,
  DIALOG_BOX_STYLES::DS_SYSMODAL,
  DIALOG_BOX_STYLES::DS_LOCALEDIT,
  DIALOG_BOX_STYLES::DS_SETFONT,
  DIALOG_BOX_STYLES::DS_MODALFRAME,
  DIALOG_BOX_STYLES::DS_NOIDLEMSG,
  DIALOG_BOX_STYLES::DS_SETFOREGROUND,
  DIALOG_BOX_STYLES::DS_3DLOOK,
  DIALOG_BOX_STYLES::DS_FIXEDSYS,
  DIALOG_BOX_STYLES::DS_NOFAILCREATE,
  DIALOG_BOX_STYLES::DS_CONTROL,
  DIALOG_BOX_STYLES::DS_CENTER,
  DIALOG_BOX_STYLES::DS_CENTERMOUSE,
  DIALOG_BOX_STYLES::DS_CONTEXTHELP,
  DIALOG_BOX_STYLES::DS_SHELLFONT,
};

// From Virtualbox - include/iprt/formats/pecoff.h
template <typename T>
struct load_configuration {
  uint32_t Characteristics;
  uint32_t TimeDateStamp;
  uint16_t MajorVersion;
  uint16_t MinorVersion;
  uint32_t GlobalFlagsClear;
  uint32_t GlobalFlagsSet;
  uint32_t CriticalSectionDefaultTimeout;
  T        DeCommitFreeBlockThreshold;
  T        DeCommitTotalFreeThreshold;
  T        LockPrefixTable;
  T        MaximumAllocationSize;
  T        VirtualMemoryThreshold;
  T        ProcessAffinityMask;
  uint32_t ProcessHeapFlags;
  uint16_t CSDVersion;
  uint16_t Reserved1;
  T        EditList;
  T        SecurityCookie;
};

template <typename T>
struct load_configuration_v0 : load_configuration<T> {
  T SEHandlerTable;
  T SEHandlerCount;
};


#pragma pack(4)
// Windows 10 - 9879

template <typename T>
struct load_configuration_v1 : load_configuration_v0<T> {
  T        GuardCFCheckFunctionPointer;
  T        GuardCFDispatchFunctionPointer;
  T        GuardCFFunctionTable;
  T        GuardCFFunctionCount;
  uint32_t GuardFlags;
};
#pragma pack()


// Windows 10 - 9879
template <typename T>
struct load_configuration_v2 : load_configuration_v1<T> {
  pe_code_integrity CodeIntegrity;
};


template <typename T>
struct load_configuration_v3 : load_configuration_v2<T> {
  T GuardAddressTakenIatEntryTable;
  T GuardAddressTakenIatEntryCount;
  T GuardLongJumpTargetTable;
  T GuardLongJumpTargetCount;
};


template <typename T>
struct load_configuration_v4 : load_configuration_v3<T> {
  T DynamicValueRelocTable;
  T HybridMetadataPointer;
};


template <typename T>
struct load_configuration_v5 : load_configuration_v4<T> {
  T        GuardRFFailureRoutine;
  T        GuardRFFailureRoutineFunctionPointer;
  uint32_t DynamicValueRelocTableOffset;
  uint16_t DynamicValueRelocTableSection;
  uint16_t Reserved2;
};


#pragma pack(4)
template <typename T>
struct load_configuration_v6 : load_configuration_v5<T> {
  T        GuardRFVerifyStackPointerFunctionPointer;
  uint32_t HotPatchTableOffset;
};
#pragma pack()

template <typename T>
struct load_configuration_v7 : load_configuration_v6<T> {
  uint32_t Reserved3;
  T        AddressOfSomeUnicodeString;
};

class PE32 {
  public:
    using pe_optional_header = pe32_optional_header;
    using pe_tls             = pe32_tls;
    using uint               = uint32_t;

    using load_configuration_t    = load_configuration<uint32_t>;
    using load_configuration_v0_t = load_configuration_v0<uint32_t>;
    using load_configuration_v1_t = load_configuration_v1<uint32_t>;
    using load_configuration_v2_t = load_configuration_v2<uint32_t>;
    using load_configuration_v3_t = load_configuration_v3<uint32_t>;
    using load_configuration_v4_t = load_configuration_v4<uint32_t>;
    using load_configuration_v5_t = load_configuration_v5<uint32_t>;
    using load_configuration_v6_t = load_configuration_v6<uint32_t>;
    using load_configuration_v7_t = load_configuration_v7<uint32_t>;


    static_assert(sizeof(load_configuration_t)    == 0x40, "");
    static_assert(sizeof(load_configuration_v0_t) == 0x48, "");
    static_assert(sizeof(load_configuration_v1_t) == 0x5c, "");
    static_assert(sizeof(load_configuration_v2_t) == 0x68, "");
    static_assert(sizeof(load_configuration_v3_t) == 0x78, "");
    static_assert(sizeof(load_configuration_v4_t) == 0x80, "");
    static_assert(sizeof(load_configuration_v5_t) == 0x90, "");
    static_assert(sizeof(load_configuration_v6_t) == 0x98, "");
    //static_assert(sizeof(LoadConfiguration_V7) == 0xA0, "");

    static const std::map<WIN_VERSION, size_t> load_configuration_sizes;
 };


class PE64 {
  public:
    using pe_optional_header = pe64_optional_header;
    using pe_tls             = pe64_tls;
    using uint               = uint64_t;

    using load_configuration_t    = load_configuration<uint64_t>;
    using load_configuration_v0_t = load_configuration_v0<uint64_t>;
    using load_configuration_v1_t = load_configuration_v1<uint64_t>;
    using load_configuration_v2_t = load_configuration_v2<uint64_t>;
    using load_configuration_v3_t = load_configuration_v3<uint64_t>;
    using load_configuration_v4_t = load_configuration_v4<uint64_t>;
    using load_configuration_v5_t = load_configuration_v5<uint64_t>;
    using load_configuration_v6_t = load_configuration_v6<uint64_t>;
    using load_configuration_v7_t = load_configuration_v7<uint64_t>;

    static_assert(sizeof(load_configuration_t)    == 0x60,  "");
    static_assert(sizeof(load_configuration_v0_t) == 0x70,  "");
    static_assert(sizeof(load_configuration_v1_t) == 0x94,  "");
    static_assert(sizeof(load_configuration_v2_t) == 0xA0,  "");
    static_assert(sizeof(load_configuration_v3_t) == 0xC0,  "");
    static_assert(sizeof(load_configuration_v4_t) == 0xD0,  "");
    static_assert(sizeof(load_configuration_v5_t) == 0xE8,  "");
    static_assert(sizeof(load_configuration_v6_t) == 0xF4,  "");
    static_assert(sizeof(load_configuration_v7_t) == 0x100, "");

    static const std::map<WIN_VERSION, size_t> load_configuration_sizes;
};



} // end namesapce ELF
}

#endif
