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

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


// Okno dialogowe CBlobHeapPage

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

CBlobHeapPage::~CBlobHeapPage()
{
}

void CBlobHeapPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BLOBLIST, m_ctrlBlobList);
}

BEGIN_MESSAGE_MAP(CBlobHeapPage, CPropertyPage)
END_MESSAGE_MAP()


// Procedury obsługi wiadomości CBlobHeapPage

int CBlobHeapPage::DumpHex(
    CListCtrl   *pList,			  // Sterowanie listą, do której przesyłane są dane
    ULONG       cRows,            // Numer obiektu typu blob.
    ULONG       oData,            // Indeks danych.
    const void  *pvData,          // Dane do wyświetlenia.
    ULONG       cbData,           // Bajty danych do wyświetlenia.
    ULONG       nLine)            // Liczba bajtów w jednym wierszu.
{
    const BYTE  *pbData = static_cast<const BYTE*>(pvData);
    ULONG i;                      // Sterowanie pętlą.
    ULONG nPrint;                 // Liczba wyświetlana w pętli.
    ULONG nSpace;                 // Obliczenie spacji.
    ULONG nLines = 0;             // Liczba wyświetlonych wierszy.
	ULONG itemIndex;
	TCHAR lBuffer[256];
	TCHAR cBuffer[64];
	
	itemIndex = pList->GetItemCount();
	memset(lBuffer, 0, sizeof(lBuffer));

    wsprintf(cBuffer, _T("%d"), cRows);
	itemIndex = pList->InsertItem(itemIndex + 1, cBuffer);

    wsprintf(cBuffer, _T("%d(0x%02x)"), oData, oData);
	pList->SetItemText(itemIndex, 1, cBuffer);

    do 
    {
        ++nLines;

		if(nLines > 1)
		{
			itemIndex = pList->InsertItem(itemIndex + 1, _T(""));
			pList->SetItemText(itemIndex, 1, _T(""));
		}

        // Obliczenie spacji.
        nPrint = min(cbData, nLine);
        nSpace = nLine - nPrint;

        // Zrzut szesnastkowy.
        for(i=0; i<nPrint; i++)
        {
            if ((i&7) == 0)
			{
              _tcscat(lBuffer, _T(" "));
			}
            wsprintf(cBuffer, _T("%02X "), pbData[i]);
			_tcscat(lBuffer, cBuffer);
        }

		pList->SetItemText(itemIndex, 2, lBuffer);

		memset(lBuffer, 0, sizeof(lBuffer));

        // Kolejne dane do wyświetlenia.
        cbData -= nPrint;
        pbData += nPrint;
    }
    while (cbData > 0);

    return nLines;
}

BOOL CBlobHeapPage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();

	CString strItemLabel = _T("Element");
	CString strIndex = _T("Indeks");
	CString strBlob = _T("Blob");

	CRect rect;
	// Wstawienie trzech kolumn (tryb raportu) i modyfikacja nowych elementów nagłówka
	m_ctrlBlobList.GetWindowRect(&rect);
	m_ctrlBlobList.InsertColumn(0, strItemLabel, LVCFMT_LEFT,
		                        rect.Width() * 1/6, 0);
	m_ctrlBlobList.InsertColumn(1, strIndex, LVCFMT_LEFT,
		                        rect.Width() * 1/6, 1);
	m_ctrlBlobList.InsertColumn(2, strBlob, 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();
	IMetaDataImport* pImport  = pDoc->MetaDataImportInterface();

	IMetaDataTables *pTables = NULL;
	HRESULT hr = pImport->QueryInterface(IID_IMetaDataTables, (void**)&pTables);

	const BYTE *pData; // Wskaźnik do obiektu blob.
    ULONG cbData;      // Wielkość obiektu blob.
    ULONG oData;       // Przesunięcie bieżącego obiektu blob.
	ULONG cRows;
    oData = 0;
	cRows = 0;
    do 
    {
        pTables->GetBlob(oData, &cbData, (const void**)&pData);
        DumpHex(&m_ctrlBlobList, cRows, oData, pData, cbData);
        hr = pTables->GetNextBlob(oData, &oData);
		cRows++;
    }
    while (hr == S_OK);

	pTables->Release();
	pTables = NULL;
	pImport->Release();

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