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

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

// Okno dialogowe CCILHeaderPage

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

CCILHeaderPage::~CCILHeaderPage()
{
}

void CCILHeaderPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_METASTREAMLIST, m_ctrlStreamList);
}

BEGIN_MESSAGE_MAP(CCILHeaderPage, CPropertyPage)
END_MESSAGE_MAP()

// CCILHeaderPage message handlers
BOOL CCILHeaderPage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();

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

	CRect rect;
	// Wstawienie dwóch kolumn (tryb raportu) i modyfikacja nowych elementów nagłówka
	m_ctrlStreamList.GetWindowRect(&rect);
	m_ctrlStreamList.InsertColumn(0, strName, LVCFMT_LEFT,
		                          (rect.Width() * 3/4) - 18, 0);
	m_ctrlStreamList.InsertColumn(1, strSize, LVCFMT_RIGHT,
		                          rect.Width() * 1/4, 1);

	// 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)
		{
			DumpCILHeader( pAssembly, pNTHeader64 );
		}
		else
		{
			DumpCILHeader( pAssembly, pNTHeader );
		}

    }

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

template <class T> void CCILHeaderPage::DumpCILHeader( PBYTE pImageBase, T* pNTHeader )	// T = PIMAGE_NT_HEADERS
{
	// CIL RVA
    DWORD CILHdrRVA;

    CILHdrRVA = GetImgDirEntryRVA(pNTHeader, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR );
    if ( !CILHdrRVA )
        return;

	PIMAGE_COR20_HEADER pCIL = (PIMAGE_COR20_HEADER)GetPtrFromRVA( CILHdrRVA, pNTHeader, pImageBase );

	CEdit* pText;
	TCHAR cBuffer[128];

	pText = (CEdit*)GetDlgItem(IDC_CILSIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->cb);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILVERSION);
	wsprintf(cBuffer, L"%u.%u", pCIL->MajorRuntimeVersion, pCIL->MinorRuntimeVersion);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILFLAGS);
	wsprintf(cBuffer, L"0x%08X", pCIL->Flags);
	pText->SetWindowText(cBuffer);

	CListBox *pList = (CListBox *)GetDlgItem(IDC_CILFLAGSLIST);
	if ( pCIL->Flags & COMIMAGE_FLAGS_ILONLY )
		pList->AddString( L"ILONLY" );
	if ( pCIL->Flags & COMIMAGE_FLAGS_32BITREQUIRED )
		pList->AddString( L"32BITREQUIRED" );
	if ( pCIL->Flags & COMIMAGE_FLAGS_IL_LIBRARY )
		pList->AddString( L"IL_LIBRARY" );
	// At this moment, WINNT.H and CorHdr.H are out of sync...
	if ( pCIL->Flags & 8 )
		pList->AddString( L"STRONGNAMESIGNED" );
	if ( pCIL->Flags & COMIMAGE_FLAGS_TRACKDEBUGDATA )
		pList->AddString( L"TRACKDEBUGDATA" );


	pText = (CEdit*)GetDlgItem(IDC_CILENTRYPOINTTOKEN);
	wsprintf(cBuffer, L"0x%08X", pCIL->EntryPointToken);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILMETARVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->MetaData.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILMETASIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->MetaData.Size);
	pText->SetWindowText(cBuffer);

	PBYTE pMeta = (PBYTE)GetPtrFromRVA( pCIL->MetaData.VirtualAddress, pNTHeader, pImageBase );
	pText = (CEdit*)GetDlgItem(IDC_METASIGNATURE);
	wsprintf(cBuffer, L"0x%08X", *((DWORD*)pMeta));
	pText->SetWindowText(cBuffer);
	pMeta += 4;

	pText = (CEdit*)GetDlgItem(IDC_METAVERSION);
	wsprintf(cBuffer, L"%u.%u", *((USHORT*)pMeta), *((USHORT*)(pMeta + 2)));
	pText->SetWindowText(cBuffer);
	pMeta += 4;

	// 4 bajty są zarezerwowane
	pMeta += 4;

	pText = (CEdit*)GetDlgItem(IDC_METAVERSIONSTRINGLENGTH);
	int versionLength = *((DWORD*)pMeta);
	wsprintf(cBuffer, L"%d", versionLength);
	pText->SetWindowText(cBuffer);
	pMeta += 4;

	// To jest UTF-8 zgodnie ze specyfikacją.
	MultiByteToWideChar(CP_UTF8, 0,			// Konwersja UTF8
		                (const char *)pMeta,	// Ciąg źrodłowy
						-1,					// Zakończony pustą wartością
						cBuffer,				// Obliczenie liczby wymaganych bajtów
						sizeof(cBuffer) / sizeof(cBuffer[0]));
	pText = (CEdit*)GetDlgItem(IDC_METAVERSIONSTRING);
	pText->SetWindowText(cBuffer);
	pMeta += versionLength;
	if((versionLength % 4) > 0)
		pMeta += 4 - (versionLength % 4);

	// 2 bajty zarezerwowane dla znaczników
	pMeta += 2;

	pText = (CEdit*)GetDlgItem(IDC_METASTREAMCOUNT);
	int metaCount = *((USHORT*)pMeta);
	wsprintf(cBuffer, L"%d", metaCount);
	pText->SetWindowText(cBuffer);
	pMeta += 2;

	PMETA_STREAM_HEADER pMetaStream;
	int itemIndex = m_ctrlStreamList.GetItemCount();
	memset(cBuffer, 0, sizeof(cBuffer));
	size_t stringLength;
	for(int i = 0;i < metaCount;i++)
	{
		pMetaStream = (PMETA_STREAM_HEADER)pMeta;
		stringLength = strlen(pMetaStream->Name);
		mbstowcs(cBuffer, pMetaStream->Name, stringLength + 1);
		itemIndex = m_ctrlStreamList.InsertItem(itemIndex + 1, cBuffer);
		wsprintf(cBuffer, L"%d", pMetaStream->Size);
		m_ctrlStreamList.SetItemText(itemIndex, 1, cBuffer);
		pMeta += 8 + stringLength + 1;
		if((8 + stringLength + 1) % 4 > 0)
			pMeta += 4 - ((8 + stringLength + 1) % 4);
	}

	pText = (CEdit*)GetDlgItem(IDC_CILRESOURCESRVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->Resources.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILRESOURCESSIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->Resources.Size);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILSTRONGNAMERVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->StrongNameSignature.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILSTRONGNAMESIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->StrongNameSignature.Size);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILCODEMANAGERRVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->CodeManagerTable.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILCODEMANAGERSIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->CodeManagerTable.Size);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILVTABLEFIXUPSRVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->VTableFixups.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILVTABLEFIXUPSSIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->VTableFixups.Size);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILEXPORTADDRTABLEJUMPSRVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->ExportAddressTableJumps.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILEXPORTADDRTABLEJUMPSSIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->ExportAddressTableJumps.Size);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILMANAGEDNATIVEHEADERRVA);
	wsprintf(cBuffer, L"0x%08X", pCIL->ManagedNativeHeader.VirtualAddress);
	pText->SetWindowText(cBuffer);

	pText = (CEdit*)GetDlgItem(IDC_CILMANAGEDNATIVEHEADERSIZE);
	wsprintf(cBuffer, L"0x%08X", pCIL->ManagedNativeHeader.Size);
	pText->SetWindowText(cBuffer);

}
