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

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


// Okno dialogowe CUserStringHeap

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

CUserStringHeapPage::~CUserStringHeapPage()
{
}

void CUserStringHeapPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_USERSTRINGLIST, m_ctrlUserStringList);
}


BEGIN_MESSAGE_MAP(CUserStringHeapPage, CPropertyPage)
END_MESSAGE_MAP()


// Procedury obsługi wiadomości CUserStringHeap

void CUserStringHeapPage::DumpUserStrings(LPWSTR pUserString, ULONG chUserString, ULONG offset, CListCtrl *pList)
{
	LPWSTR		szUserString;
	ULONG       itemIndex;
	WCHAR       cBuffer[64];
    bool        bUnprint = false;

	itemIndex = pList->GetItemCount();
	memset(cBuffer, 0, sizeof(cBuffer));

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

	wsprintf(cBuffer, _T("0x%8X"),  0x70 << 24 | offset);
	pList->SetItemText(itemIndex, 1, cBuffer);

	szUserString = pUserString;
	std::wstring userString;
	while (chUserString)
	{   
		switch (*szUserString)
		{
		case 0:
			userString += L"\\0";
			break;
		case L'\r':
			userString += L"\\r";
			break;
		case L'\n':
			userString += L"\\n";
			break;
		case L'\t':
			userString += L"\\t";
			break;
		default:
			if (iswprint(*szUserString))
			{
				userString += *szUserString;
			}
			else 
			{
				bUnprint = true;
				userString += L".";
			}
			break;
		}
		++szUserString;
		chUserString -= 2;
	}
	pList->SetItemText(itemIndex, 2, userString.c_str());
}


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

	CString strItemLabel = _T("Item");
	CString strIndex = _T("Token");
	CString strString = _T("String");

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

	// Wypełnienie danymi.
	CPropertySheet *pPropertySheet = STATIC_DOWNCAST(CPropertySheet, GetParent());
	CAssemblyView* pView = STATIC_DOWNCAST(CAssemblyView, pPropertySheet->GetParent());

	PBYTE userStringTable = pView->UserStringTable();
	DWORD userStringTableSize = pView->UserStringTableSize();
    ULONG cbData;		// Długość ciągu.
    ULONG oData = 1;	// Przesunięcie bieżącego ciągu.
	ULONG cRows = 1;
	ULONG offset;

    do 
    {
		offset = oData;
		oData += CorSigUncompressData(userStringTable + oData, &cbData);
		if(cbData != 0)
			DumpUserStrings((LPWSTR)(userStringTable + oData), cbData - 1, offset, &m_ctrlUserStringList);
		cRows++;
		oData += cbData;
    }
    while (oData < userStringTableSize);

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