//
// 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.
//
// 
#pragma once

typedef enum
{
	Branch = 0,
	Token,
	Index,
	Value,
	Switch,
	None
} OperandType;

struct opcode
{
public:
	opcode()
	{
		operandSize = 0;
	}
	opcode(const std::wstring& instr) :
	       instruction(instr),
		   operandSize(0),
		   operandType(None)
	{
	}
	opcode(const std::wstring& instr, int os, OperandType t) :
	       instruction(instr),
		   operandSize(os),
		   operandType(t)
	{
	}
	std::wstring Instruction() const
	{
		return instruction;
	}
	int OperandSize() const
	{
		return operandSize;
	}
	OperandType Type() const
	{
		return operandType;
	}
private:
	std::wstring instruction;
	int operandSize;
	OperandType operandType;
};

typedef std::map<BYTE, opcode> ILCodeMap;
typedef ILCodeMap::const_iterator ILCodeMapConstantIterator;
typedef ILCodeMap::iterator ILCodeMapIterator;


class CCILOpcode
{
public:
	CCILOpcode(PBYTE source, int count);
	~CCILOpcode(void);
	bool Next();
	std::wstring Instruction()
	{
		return instructionString;
	}
	int OperandSize()
	{
		return current.OperandSize();
	}
	PBYTE Operand()
	{
		return operand;
	}
	bool IsSwitch() const
	{
		return current.Type() == Switch;
	}
	bool IsBranch() const
	{
		return current.Type() == Branch;
	}
	bool IsToken() const
	{
		return current.Type() == Token;
	}
	bool IsIndex() const
	{
		return current.Type() == Index;
	}
	bool IsValue() const
	{
		return current.Type() == Value;
	}
	DWORD SwitchCount() const
	{
		if(!isSwitch) return 0;
		return switchCount;
	}
	DWORD SwitchNext()
	{
		if(!isSwitch) return 0;
		if(switchCount < 0) return 0;
		DWORD ret = *((DWORD*)operand);
		operand += 4;
		switchCount--;
		return ret;
	}
	bool IsEnd() const
	{
		return index >= count;
	}
private:
	CCILOpcode(void);
	static void BuildMap(ILCodeMap& m, ILCodeMap& n);
	bool IsPrefix(byte b)
	{
		if(b == 0xfe)
			return true;
		else
			return false;
	}
	static ILCodeMap oneByteOpcodes;
	static ILCodeMap twoByteOpcodes;
	static bool initialized;
	PBYTE source;
	int count;
	int index;
	opcode current;
	std::wstring instructionString;
	PBYTE operand;
	bool isSwitch;
	int switchCount;
};
