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

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

/*----------------------------------------------------------------------------*/
//
// Elementy związane z sekcjami
//
/*----------------------------------------------------------------------------*/
typedef struct
{
    DWORD   flag;
    PWSTR    name;
} DWORD_FLAG_DESCRIPTIONS;

// Wartości pól bitowych i nazwy znaczników IMAGE_SECTION_HEADER.
DWORD_FLAG_DESCRIPTIONS SectionCharacteristics[] = 
{
	{ IMAGE_SCN_TYPE_NO_PAD, L"NO_PAD" },
	{ IMAGE_SCN_CNT_CODE, L"CODE" },
	{ IMAGE_SCN_CNT_INITIALIZED_DATA, L"INITIALIZED_DATA" },
	{ IMAGE_SCN_CNT_UNINITIALIZED_DATA, L"UNINITIALIZED_DATA" },
	{ IMAGE_SCN_LNK_OTHER, L"OTHER" },
	{ IMAGE_SCN_LNK_INFO, L"INFO" },
	{ IMAGE_SCN_LNK_REMOVE, L"REMOVE" },
	{ IMAGE_SCN_LNK_COMDAT, L"COMDAT" },
	{ IMAGE_SCN_MEM_FARDATA, L"FARDATA" },
	{ IMAGE_SCN_MEM_PURGEABLE, L"PURGEABLE" },
	{ IMAGE_SCN_MEM_LOCKED, L"LOCKED" },
	{ IMAGE_SCN_MEM_PRELOAD, L"PRELOAD" },
	{ IMAGE_SCN_LNK_NRELOC_OVFL, L"NRELOC_OVFL" },
	{ IMAGE_SCN_MEM_DISCARDABLE, L"DISCARDABLE" },
	{ IMAGE_SCN_MEM_NOT_CACHED, L"NOT_CACHED" },
	{ IMAGE_SCN_MEM_NOT_PAGED, L"NOT_PAGED" },
	{ IMAGE_SCN_MEM_SHARED, L"SHARED" },
	{ IMAGE_SCN_MEM_EXECUTE, L"EXECUTE" },
	{ IMAGE_SCN_MEM_READ, L"READ" },
	{ IMAGE_SCN_MEM_WRITE, L"WRITE" },
};

#define NUMBER_SECTION_CHARACTERISTICS \
    (sizeof(SectionCharacteristics) / sizeof(DWORD_FLAG_DESCRIPTIONS))

// Liczba znaków szesnastkowych wyświetlanych w wierszu.
#define HEX_DUMP_WIDTH 16

//
// Zrzut obszaru pamięci w formacie szesnastkowym.
//
void CSectionPage::HexDump(PBYTE ptr, DWORD length, HTREEITEM treeDataItem)
{
    wchar_t buffer[512];
    PWSTR buffPtr, buffPtr2;
    unsigned cOutput, i;
    DWORD bytesToGo=length;

    while ( bytesToGo  )
    {
        cOutput = bytesToGo >= HEX_DUMP_WIDTH ? HEX_DUMP_WIDTH : bytesToGo;

        buffPtr = buffer;
        buffPtr += wsprintf(buffPtr, L"%08X:  ", length-bytesToGo );
        buffPtr2 = buffPtr + (HEX_DUMP_WIDTH * 3) + 1;
        
        for ( i=0; i < HEX_DUMP_WIDTH; i++ )
        {
            BYTE value = *(ptr+i);

            if ( i >= cOutput )
            {
                // Przejście do ostatniego wiersza. Uzupełnienie spacjami.
                *buffPtr++ = L' ';
                *buffPtr++ = L' ';
                *buffPtr++ = L' ';
            }
            else
            {
                if ( value < 0x10 )
                {
                    *buffPtr++ = L'0';
                    _itow( value, buffPtr++, 16);
 					buffPtr[0] = towupper(buffPtr[0]);
					buffPtr[1] = towupper(buffPtr[1]);
               }
                else
                {
                    _itow( value, buffPtr, 16);
					buffPtr[0] = towupper(buffPtr[0]);
					buffPtr[1] = towupper(buffPtr[1]);
                    buffPtr+=2;
                }
 
                *buffPtr++ = L' ';
                *buffPtr2++ = iswprint(value) ? value : L'.';
            }
            
            // Umieszczenie w każdym wierszu dodatkowej spacji między pierwszą i drugą 
            // połową bajtów.
            if ( i == (HEX_DUMP_WIDTH/2)-1 )
                *buffPtr++ = L' ';
        }

        *buffPtr2 = 0;  // Zakończenie pustą wartością.
		m_ctrlSectionTableTree.InsertItem(buffer, treeDataItem);
        bytesToGo -= cOutput;
        ptr += HEX_DUMP_WIDTH;
    }
}

void CSectionPage::DumpRawSectionData(PIMAGE_SECTION_HEADER section, PVOID base, HTREEITEM treeDataItem)
{
    // Nie należy wykonywać zrzutu sekcji, które nie istnieją w pliku!
    if ( section->PointerToRawData == 0 )
            return;

    HexDump( MakePtr(PBYTE, base, section->PointerToRawData),
             section->SizeOfRawData,
			 treeDataItem);
}

//
// Zrzut tablicy sekcji z pliku PE lub OBJ.
//
void CSectionPage::DumpSectionTable(PIMAGE_SECTION_HEADER section,
                                    unsigned cSections,
                                    BOOL IsEXE,
									PIMAGE_DOS_HEADER dosHeader,
									PIMAGE_SECTION_HEADER pRawSectionData)
{
 	WCHAR lBuffer[256];  
	HTREEITEM treeRowItem;
	HTREEITEM treeCharacteristicItem;
	HTREEITEM treeDataItem;

    for ( unsigned i=1; i <= cSections; i++, section++ )
    {
		mbstowcs(lBuffer, (const char *)section->Name, strlen((const char *)section->Name) + 1);
		treeRowItem = m_ctrlSectionTableTree.InsertItem(lBuffer);
		wsprintf(lBuffer, L"%ls         : 0x%08X Adres wirtualny             : 0x%08X",
			     IsEXE ? L"Wielkość wirt." : L"Adres fizyczny",
				 section->Misc.VirtualSize,
				 section->VirtualAddress);
		m_ctrlSectionTableTree.InsertItem(lBuffer, treeRowItem);

		wsprintf(lBuffer, L"Przesunięcie danych pierwotnych: 0x%08X Wielkość danych pierwotnych: 0x%08X",
				 section->PointerToRawData,
				 section->SizeOfRawData);
		m_ctrlSectionTableTree.InsertItem(lBuffer, treeRowItem);

		wsprintf(lBuffer, L"Przesunięcie relokacji: 0x%08X Liczba relokacji: 0x%08X",
				 section->PointerToRelocations,
				 section->NumberOfRelocations);
		m_ctrlSectionTableTree.InsertItem(lBuffer, treeRowItem);

		wsprintf(lBuffer, L"Przesunięcie numeru wiersza: 0x%08X Liczba wierszy: 0x%08X",
				 section->PointerToLinenumbers,
				 section->NumberOfLinenumbers);
		m_ctrlSectionTableTree.InsertItem(lBuffer, treeRowItem);

		wsprintf(lBuffer, L"Charakterystyka: 0x%08X",
				 section->Characteristics);
		treeCharacteristicItem = m_ctrlSectionTableTree.InsertItem(lBuffer, treeRowItem);

        for ( unsigned j=0; j < NUMBER_SECTION_CHARACTERISTICS; j++ )
        {
            if ( section->Characteristics & 
                SectionCharacteristics[j].flag )
				m_ctrlSectionTableTree.InsertItem(SectionCharacteristics[j].name, treeCharacteristicItem);
        }

		unsigned alignment = (section->Characteristics & IMAGE_SCN_ALIGN_MASK);
		if ( alignment == 0 )
		{
			m_ctrlSectionTableTree.InsertItem(L"ALIGN_DEFAULT(16)", treeCharacteristicItem);
		}
		else
		{
			// Yeah, it's hard to read this, but it works, and it's elegant
			alignment = alignment >>= 20;
			wsprintf(lBuffer, L"ALIGN_%uBYTES",
				      1 << (alignment-1));
			m_ctrlSectionTableTree.InsertItem(lBuffer, treeCharacteristicItem);
		}
		treeDataItem = m_ctrlSectionTableTree.InsertItem(L"Dane", treeRowItem);
		DumpRawSectionData(pRawSectionData, dosHeader, treeDataItem);
    }
}

// Okno dialogowe CSectionPage

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

CSectionPage::~CSectionPage()
{
	sectionFont.DeleteObject();
}

void CSectionPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_SECTIONTABLETREE, m_ctrlSectionTableTree);
}

BEGIN_MESSAGE_MAP(CSectionPage, CPropertyPage)
END_MESSAGE_MAP()

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

	// Inicjalizacja obiektu CFont o charakterystyce zależnej 
	// od struktury LOGFONT.
	LOGFONT lf;
	memset(&lf, 0, sizeof(LOGFONT));              // wyzerowanie struktury
	lf.lfHeight = 18;                             // żądanie czcionki 12-pikselowej
	wcscpy(lf.lfFaceName, L"Ansi");               // żądanie czcionki "Arial"
	lf.lfPitchAndFamily = FIXED_PITCH;
	VERIFY(sectionFont.CreateFontIndirect(&lf));  // utworzenie czcionki
	m_ctrlSectionTableTree.SetFont(&sectionFont);

	// Fill in the data
	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 );

// // IMAGE_FIRST_SECTION nie wymaga wersji 32/64, ponieważ nagłówek pliku
   // jest identyczny w obu przypadkach.
//
// #define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER)        \
//    ((ULONG_PTR)ntheader +                                              \
//     FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) +                 \
//     ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader   \
//    ))
// #define FIELD_OFFSET(type, field)    ((LONG)(LONG_PTR)&(((type *)0)->field))

		PIMAGE_SECTION_HEADER pRawSectionData;

		pRawSectionData = bIs64Bit ? (PIMAGE_SECTION_HEADER)(pNTHeader64+1) : (PIMAGE_SECTION_HEADER)(pNTHeader+1);

		DumpSectionTable( IMAGE_FIRST_SECTION(pNTHeader), 
                          pNTHeader->FileHeader.NumberOfSections,
						  TRUE,
						  dosHeader,
						  pRawSectionData);
    }

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