//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
// FileHeaderProprertiesPage.cpp : plik implementacji
//

#include "stdafx.h"
#include "AssemblyDoc.h"
#include "AssemblyView.h"
#include "FileHeaderPropertiesPage.h"

typedef struct
{
	WORD	wValue;
	PWSTR	pszName;
} WORD_VALUE_NAMES;

#define ARRAY_SIZE( x ) (sizeof(x) / sizeof(x[0]))

typedef struct
{
    WORD    flag;
    PWSTR    name;
} WORD_FLAG_DESCRIPTIONS;

// Wartości pól bitowych i nazwy znaczników IMAGE_FILE_HEADER
static WORD_FLAG_DESCRIPTIONS ImageFileHeaderCharacteristics[] = 
{
{ IMAGE_FILE_RELOCS_STRIPPED, L"RELOCS_STRIPPED" },
{ IMAGE_FILE_EXECUTABLE_IMAGE, L"EXECUTABLE_IMAGE" },
{ IMAGE_FILE_LINE_NUMS_STRIPPED, L"LINE_NUMS_STRIPPED" },
{ IMAGE_FILE_LOCAL_SYMS_STRIPPED, L"LOCAL_SYMS_STRIPPED" },
{ IMAGE_FILE_AGGRESIVE_WS_TRIM, L"AGGRESIVE_WS_TRIM" },
{ IMAGE_FILE_LARGE_ADDRESS_AWARE, L"LARGE_ADDRESS_AWARE" },
{ IMAGE_FILE_BYTES_REVERSED_LO, L"BYTES_REVERSED_LO" },
{ IMAGE_FILE_32BIT_MACHINE, L"32BIT_MACHINE" },
{ IMAGE_FILE_DEBUG_STRIPPED, L"DEBUG_STRIPPED" },
{ IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, L"REMOVABLE_RUN_FROM_SWAP" },
{ IMAGE_FILE_NET_RUN_FROM_SWAP, L"NET_RUN_FROM_SWAP" },
{ IMAGE_FILE_SYSTEM, L"SYSTEM" },
{ IMAGE_FILE_DLL, L"DLL" },
{ IMAGE_FILE_UP_SYSTEM_ONLY, L"UP_SYSTEM_ONLY" },
{ IMAGE_FILE_BYTES_REVERSED_HI, L"BYTES_REVERSED_HI" }
// { IMAGE_FILE_MINIMAL_OBJECT, "MINIMAL_OBJECT" }, // Usunięty w NT 3.5
// { IMAGE_FILE_UPDATE_OBJECT, "UPDATE_OBJECT" },   // Usunięty w NT 3.5
// { IMAGE_FILE_16BIT_MACHINE, "16BIT_MACHINE" },   // Usunięty w NT 3.5
// { IMAGE_FILE_PATCH, "PATCH" },
};

#define NUMBER_IMAGE_HEADER_FLAGS \
    (sizeof(ImageFileHeaderCharacteristics) / sizeof(WORD_FLAG_DESCRIPTIONS))

static WORD_VALUE_NAMES arMachines[] = 
{
{ IMAGE_FILE_MACHINE_UNKNOWN, L"UNKNOWN" },
{ IMAGE_FILE_MACHINE_I386, L"I386" },
{ IMAGE_FILE_MACHINE_R3000, L"R3000" },
{ IMAGE_FILE_MACHINE_R4000, L"R4000" },
{ IMAGE_FILE_MACHINE_R10000, L"R10000" },
{ IMAGE_FILE_MACHINE_WCEMIPSV2, L"WCEMIPSV2" },
{ IMAGE_FILE_MACHINE_ALPHA, L"ALPHA" },
{ IMAGE_FILE_MACHINE_SH3, L"SH3" },
{ IMAGE_FILE_MACHINE_SH3DSP, L"SH3DSP" },
{ IMAGE_FILE_MACHINE_SH3E, L"SH3E" },
{ IMAGE_FILE_MACHINE_SH4, L"SH4" },
{ IMAGE_FILE_MACHINE_SH5, L"SH5" },
{ IMAGE_FILE_MACHINE_ARM, L"ARM" },
{ IMAGE_FILE_MACHINE_THUMB, L"THUMB" },
{ IMAGE_FILE_MACHINE_AM33, L"AM33" },
{ IMAGE_FILE_MACHINE_POWERPC, L"POWERPC" },
{ IMAGE_FILE_MACHINE_POWERPCFP, L"POWERPCFP" },
{ IMAGE_FILE_MACHINE_IA64, L"IA64" },
{ IMAGE_FILE_MACHINE_MIPS16, L"MIPS16" },
{ IMAGE_FILE_MACHINE_ALPHA64, L"ALPHA64" },
{ IMAGE_FILE_MACHINE_MIPSFPU, L"MIPSFPU" },
{ IMAGE_FILE_MACHINE_MIPSFPU16, L"MIPSFPU16" },
{ IMAGE_FILE_MACHINE_TRICORE, L"TRICORE" },
{ IMAGE_FILE_MACHINE_CEF, L"CEF" },
{ IMAGE_FILE_MACHINE_EBC, L"EBC" },
{ IMAGE_FILE_MACHINE_AMD64, L"AMD64" },
{ IMAGE_FILE_MACHINE_M32R, L"M32R" },
{ IMAGE_FILE_MACHINE_CEE, L"CEE" },
};

static bool IsValidMachineType( WORD wMachineType )
{
	for ( unsigned i = 0; i < ARRAY_SIZE(arMachines); i++ )
		if ( wMachineType == arMachines[i].wValue )
			return true;

	return false;
}

static PWSTR GetMachineTypeName( WORD wMachineType )
{
	for ( unsigned i = 0; i < ARRAY_SIZE(arMachines); i++ )
		if ( wMachineType == arMachines[i].wValue )
			return arMachines[i].pszName;

	return L"unknown";
}

// Okno dialogowe CFileHeaderPropertiesPage

IMPLEMENT_DYNAMIC(CFileHeaderPropertiesPage, CPropertyPage)
CFileHeaderPropertiesPage::CFileHeaderPropertiesPage()
	: CPropertyPage(CFileHeaderPropertiesPage::IDD)
{
}

CFileHeaderPropertiesPage::~CFileHeaderPropertiesPage()
{
}

void CFileHeaderPropertiesPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CFileHeaderPropertiesPage, CPropertyPage)
END_MESSAGE_MAP()

void CFileHeaderPropertiesPage::DumpHeader(PIMAGE_FILE_HEADER pImageFileHeader)
{
	CEdit* pText;
	TCHAR cBuffer[128];

	pText = (CEdit*)GetDlgItem(IDC_MACHINEDESCRIPTION);
    wsprintf(cBuffer, L"0x%04X (%ls)", 
                      pImageFileHeader->Machine,
                      GetMachineTypeName(pImageFileHeader->Machine) );
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_SECTIONCOUNT);
    wsprintf(cBuffer, L"%d", 
                      pImageFileHeader->NumberOfSections);
	pText->SetWindowText(cBuffer);

	time_t timeStamp = pImageFileHeader->TimeDateStamp;
	pText = (CEdit*)GetDlgItem(IDC_TIMESTAMP);
    wcscpy(cBuffer, _wctime(&timeStamp));
	for(size_t i = wcslen(cBuffer) - 1;
		cBuffer[i] == L'\n' ||
		cBuffer[i] == L'\r' ||
		cBuffer[i] == L' ';
	    --i)
	{
		cBuffer[i] = L'\0';
	}
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_SYMBOLTABLEPOINTER);
    wsprintf(cBuffer, L"0x%08X", 
                      pImageFileHeader->PointerToSymbolTable);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_SYMBOLTABLESIZE);
    wsprintf(cBuffer, L"%d", 
                      pImageFileHeader->NumberOfSymbols);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_OPTIONALHEADERSIZE);
    wsprintf(cBuffer, L"%d", 
                      pImageFileHeader->SizeOfOptionalHeader);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_RAWCHARACTERISTICS);
    wsprintf(cBuffer, L"0x%08X", 
                      pImageFileHeader->Characteristics);
	pText->SetWindowText(cBuffer);

	CListBox *pList = (CListBox *)GetDlgItem(IDC_CHARACTERISTICLIST);
    for (int i=0; i < NUMBER_IMAGE_HEADER_FLAGS; i++)
    {
        if ( pImageFileHeader->Characteristics & 
             ImageFileHeaderCharacteristics[i].flag )
		{
			pList->AddString(ImageFileHeaderCharacteristics[i].name);
		}
    }
}

//typedef struct _IMAGE_DOS_HEADER {      // Nagłówek DOS .EXE
//     0 WORD   e_magic;                     // Magiczna liczba
//     2 WORD   e_cblp;                      // Liczba bajtów na ostatniej stronicy pliku
//     4 WORD   e_cp;                        // Liczba stronic w pliku
//     6 WORD   e_crlc;                      // Relokacje
//     8 WORD   e_cparhdr;                   // Wielkość nagłówka bloku
//    10 WORD   e_minalloc;                  // Minimalna liczba dodatkowych bloków
//    12 WORD   e_maxalloc;                  // Maksymalna liczba dodatkowych bloków
//    14 WORD   e_ss;                        // Wstępna (relatywna) wartość SS
//    16 WORD   e_sp;                        // Wstępna wartość SP
//    18 WORD   e_csum;                      // Suma kontrolna
//    20 WORD   e_ip;                        // Wstępna wartość IP
//    22 WORD   e_cs;                        // Wstępna (relatywna) wartość CS
//    24 WORD   e_lfarlc;                    // Adres pliku tablicy relokacji
//    26 WORD   e_ovno;                      // Numer nakładki
//    28 WORD   e_res[4];                    // Zarezerwowane słowa
//    36 WORD   e_oemid;                     // Identyfikator OEM (dla e_oeminfo)
//    38 WORD   e_oeminfo;                   // Informacje OEM dla e_oemid
//    40 WORD   e_res2[10];                  // Zarezerwowane słowa
//    60 LONG   e_lfanew;                    // Adres pliku nowego nagłówka exe
//  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

// Procedury obsługi wiadomości CFileHeaderPropertiesPage
BOOL CFileHeaderPropertiesPage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();

	// Wypełnienie danymi
	CPropertySheet *pPropertySheet = STATIC_DOWNCAST(CPropertySheet, GetParent());
	CAssemblyView* pView = STATIC_DOWNCAST(CAssemblyView, pPropertySheet->GetParent());
	CAssemblyDoc* pDoc = pView->GetDocument();
	PBYTE pAssembly = pDoc->FileData();
	PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)pAssembly;
	PIMAGE_FILE_HEADER pImgFileHdr = (PIMAGE_FILE_HEADER)pAssembly;
	CEdit* pText;
	TCHAR cBuffer[128];
	pText = (CEdit*)GetDlgItem(IDC_FILETYPE);
    if ( dosHeader->e_magic == IMAGE_DOS_SIGNATURE )
    {
		// Nagłówek DOS obecny
		wcscpy(cBuffer, L"Magiczna liczba DOS");
		pText->SetWindowText(cBuffer);

		PIMAGE_NT_HEADERS pNTHeader;
		PIMAGE_NT_HEADERS64 pNTHeader64;

		// Utworzenie wskaźników do 32- i 64-bitowej wersji nagłówka.
		pNTHeader = MakePtr( PIMAGE_NT_HEADERS,
			                 dosHeader,
							 dosHeader->e_lfanew );

		pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader;
		// Najpierw weryfikacja, czy pole e_lfanew przekazało właściwy wskaźnik,
		// a następnie weryfikacja sygnatury PE.
		if ( IsBadReadPtr( pNTHeader, sizeof(pNTHeader->Signature) ) )
		{
			ATLTRACE(L"To nie jest plik typu Portable Executable (PE) EXE\n");
			return FALSE;
		}

		if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
		{
			ATLTRACE(L"To nie jest plik typu Portable Executable (PE) EXE\n");
			return FALSE;
		}

		pText = (CEdit*)GetDlgItem(IDC_HEADEROFFSET);
		wsprintf(cBuffer, L"0x%08X", dosHeader->e_lfanew);
		pText->SetWindowText(cBuffer);

		DumpHeader((PIMAGE_FILE_HEADER)&pNTHeader->FileHeader);
    }
    else if ( dosHeader->e_magic == IMAGE_SEPARATE_DEBUG_SIGNATURE )
    {
		// Oddzielna sygnatura debug
		wcscpy(cBuffer, L"Separate Debug");
		pText->SetWindowText(cBuffer);
   }
    else if ( IsValidMachineType(pImgFileHdr->Machine) )
    {
		// Opcjonalny nagłówek 0 
		if ( 0 == pImgFileHdr->SizeOfOptionalHeader )
		{
			// oznacza, że jest to OBJ
			wcscpy(cBuffer, L"OBJ");
			pText->SetWindowText(cBuffer);
		}
		else if (pImgFileHdr->SizeOfOptionalHeader
				     == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER )
		{
			// Obraz ROM
 			wcscpy(cBuffer, L"ROM");
			pText->SetWindowText(cBuffer);
		}
    }
    else if ( 0 == strncmp((char *)pAssembly,
		                   IMAGE_ARCHIVE_START,
                           IMAGE_ARCHIVE_START_SIZE) )
    {
		// Plik Lib
		wcscpy(cBuffer, L"LIB");
		pText->SetWindowText(cBuffer);
    }
    else
	{
		// Unrecognized file type
		wcscpy(cBuffer, L"Nierozpoznany typ pliku");
		pText->SetWindowText(cBuffer);
	}

	return TRUE;  // zwrócenie TRUE, chyba że ognisko ustawiono na element sterujący
}
