//
// 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.
//
// 
// DataDirectoryPage.cpp : plik implementacji
//

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

// Nazwy zdefiniowanych elementów katalogu danych
LPWSTR ImageDirectoryNames[] = {
    L"EXPORT",
	L"IMPORT",
	L"RESOURCE",
	L"EXCEPTION",
	L"SECURITY",
	L"BASERELOC",
    L"DEBUG",
	L"ARCHITECTURE",
	L"GLOBALPTR",
	L"TLS",
	L"LOAD_CONFIG",
    L"BOUND_IMPORT",  		// Dwa elementy dodane dla NT 3.51
	L"IAT",
	L"DELAY_IMPORT",		// Ten element dodany do ramki czasu NT 5
	L"COM_DESCRPTR" };		// Dla modułu wykonawczego .NET (wcześniej nazywanego COM+ 2.0)

#define NUMBER_IMAGE_DIRECTORY_ENTRYS \
    (sizeof(ImageDirectoryNames)/sizeof(LPWSTR))

// Okno dialogowe CDataDirectoryPage

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

CDataDirectoryPage::~CDataDirectoryPage()
{
}

void CDataDirectoryPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_DATADIRECTORYLIST, m_ctrlDataDirectoryList);
}

BEGIN_MESSAGE_MAP(CDataDirectoryPage, CPropertyPage)
END_MESSAGE_MAP()

void CDataDirectoryPage::DisplayDataDirectoryEntry( PWSTR pszName, IMAGE_DATA_DIRECTORY & dataDirEntry )
{
	TCHAR cBuffer[128];

	int itemIndex = m_ctrlDataDirectoryList.GetItemCount();
	memset(cBuffer, 0, sizeof(cBuffer));

	itemIndex = m_ctrlDataDirectoryList.InsertItem(itemIndex + 1, pszName);

    wsprintf(cBuffer, L"0x%08X", dataDirEntry.VirtualAddress);
	m_ctrlDataDirectoryList.SetItemText(itemIndex, 1, cBuffer);

    wsprintf(cBuffer, L"0x%08X", dataDirEntry.Size);
	m_ctrlDataDirectoryList.SetItemText(itemIndex, 2, cBuffer);
}

template <class T> void CDataDirectoryPage::DumpDataDirectory(T* pImageOptionalHeader)		// 'T' to IMAGE_OPTIONAL_HEADER32/64
{
    if(pImageOptionalHeader->NumberOfRvaAndSizes == 0)
		return;

    for (unsigned int i=0; i < pImageOptionalHeader->NumberOfRvaAndSizes; i++)
    {
		DisplayDataDirectoryEntry( (i >= NUMBER_IMAGE_DIRECTORY_ENTRYS) ? L"unused" : ImageDirectoryNames[i],
									pImageOptionalHeader->DataDirectory[i] );
    }
}

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

	CString strName = _T("Nazwa");
	CString strAddress = _T("Adres");
	CString strSize = _T("Wielkość");

	CRect rect;
	// Wstawienie trzech kolumn (tryb raportu) i modyfikacja nowych elementów nagłówka
	m_ctrlDataDirectoryList.GetWindowRect(&rect);
	m_ctrlDataDirectoryList.InsertColumn(0, strName, LVCFMT_LEFT,
		                        rect.Width() * 1/6, 0);
	m_ctrlDataDirectoryList.InsertColumn(1, strAddress, LVCFMT_LEFT,
		                        rect.Width() * 1/6, 1);
	m_ctrlDataDirectoryList.InsertColumn(2, strSize, LVCFMT_LEFT,
		                        rect.Width() * 2/3, 2);

	// 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;
    if ( dosHeader->e_magic == IMAGE_DOS_SIGNATURE )
    {
		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;
		}

		bool bIs64Bit = ( pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC );

		if ( bIs64Bit )
			DumpDataDirectory(&pNTHeader64->OptionalHeader);
		else
			DumpDataDirectory(&pNTHeader->OptionalHeader);
    }

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