/*
Copyright (C) 2006 Evan Teran
                   eteran@alum.rit.edu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "Instruction.h"
#include <iostream>
#include <sstream>
#include <cassert>
#include <exception>

#include "OPTable_FPU.tcc"
#include "OPTable_1byte.tcc"
#include "OPTable_2byte.tcc"
#include "OPTable_3byte.tcc"
#include "OPTable_Group1.tcc"
#include "OPTable_Group2.tcc"
#include "OPTable_Group3.tcc"
#include "OPTable_Group4.tcc"
#include "OPTable_Group5.tcc"
#include "OPTable_Group6.tcc"
#include "OPTable_Group7.tcc"
#include "OPTable_Group8.tcc"
#include "OPTable_Group9.tcc"
#include "OPTable_Group10.tcc"
#include "OPTable_Group11.tcc"
#include "OPTable_Group12.tcc"
#include "OPTable_Group13.tcc"
#include "OPTable_Group14.tcc"
#include "OPTable_Group15.tcc"
#include "OPTable_Group16.tcc"
#include "OPTable_Group17.tcc"

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
Instruction::Instruction(const uint8_t *buf, std::size_t size, uint64_t rva, const std::nothrow_t&) throw()
		: m_RIP(rva), m_Opcode(0), m_Type(OP_INVALID), m_Prefix(0), m_MandatoryPrefix(0),
		m_OperandCount(0), m_ModRMSize(0), m_SIBSize(0), m_DispSize(0), m_PrefixSize(0), 
		m_ImmidiateSize(0), m_OpcodeSize(0) {
		
	try {
		initialize(buf, size);
	} catch(instruction_too_big) {
		//throw;
	} catch(invalid_operand) {
		//throw;
	} catch(invalid_instruction) {
		//throw;
	}


}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
Instruction::Instruction(const uint8_t *buf, std::size_t size, uint64_t rva) 
		: m_RIP(rva), m_Opcode(0), m_Type(OP_INVALID), m_Prefix(0), m_MandatoryPrefix(0),
		m_OperandCount(0), m_ModRMSize(0), m_SIBSize(0), m_DispSize(0), m_PrefixSize(0), 
		m_ImmidiateSize(0), m_OpcodeSize(0) {
		
	initialize(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::initialize(const uint8_t *buf, std::size_t &size) {
	processPrefixes(buf, size);
	
	m_Operands[0].m_Type = Operand::TYPE_INVALID;
	m_Operands[1].m_Type = Operand::TYPE_INVALID;
	m_Operands[2].m_Type = Operand::TYPE_INVALID;
	
	if(size > 0) {
		// find the entry in the table
		m_Opcode = &m_Opcodes[*buf];	
		m_OpcodeSize = 1;

		(this->*(m_Opcode->decoder))(buf, size);
		m_Type		= m_Opcode->type;
		m_Mnemonic	= m_Opcode->mnemonic;
	}
}

//------------------------------------------------------------------------------
// Name: processPrefixes(const uint8_t *&buf, std::size_t &size)
//------------------------------------------------------------------------------
void Instruction::processPrefixes(const uint8_t *&buf, std::size_t &size) {

	bool done = false;
	
	// we only allow one prefix from each group to be set,
	// currently, the last one from a given group in the stream
	// will take precidence
	
	do {
		if(size == 0) {
			break;
		}
		
		switch(*buf) {
		// group1
		case 0xf0:
			m_Prefix = (m_Prefix & 0xffffff00) | PREFIX_LOCK;
			break;
		case 0xf2:
			m_Prefix = (m_Prefix & 0xffffff00) | PREFIX_REPNE;
			break;
		case 0xf3:
			m_Prefix = (m_Prefix & 0xffffff00) | PREFIX_REP;
			break;
		// group2
		case 0x2e:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_CS;
			break;
		case 0x36:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_SS;
			break;
		case 0x3e:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_DS;
			break;
		case 0x26:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_ES;
			break;
		case 0x64:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_FS;
			break;
		case 0x65:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_GS;
			break;
		#if 0
		case 0x2e:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_BRANCH_NOT_TAKEN;
			break;
		case 0x3e:
			m_Prefix = (m_Prefix & 0xffff00ff) | PREFIX_BRANCH_TAKEN;
			break;	
		#endif
		// group3
		case 0x66:
			m_Prefix = (m_Prefix & 0xff00ffff) | PREFIX_OPERAND;
			break;
		// group4
		case 0x67:
			m_Prefix = (m_Prefix & 0x00ffffff) | PREFIX_ADDRESS;
			break;
		default:
			done = true;
			break;
		}

		if(!done) {
			++buf;
			++m_PrefixSize;
			--size;
		}
	} while(!done);
}

//------------------------------------------------------------------------------
// Name: nextOperand()
//------------------------------------------------------------------------------
Operand &Instruction::nextOperand() {
	Operand &ret = m_Operands[m_OperandCount++];
	ret.m_Owner = this;
	return ret;
}

//------------------------------------------------------------------------------
// Name: decode_invalid(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_invalid(const uint8_t *buf, std::size_t size) {
	UNUSED(buf);
	UNUSED(size);
	throw invalid_instruction(Instruction::size());
}

#define EMIT_ALT_NAME_HANDLER(name1, name2, pfx, decoder_func, OP1, OP2) \
void Instruction::decode_ ## name1 ## _ ## name2 (const uint8_t *buf, std::size_t size) {	\
	static OpcodeEntry opcodes[] = {				\
		{ #name1, (decoder_func), OP1 },			\
		{ #name2, (decoder_func), OP2 }				\
	};												\
	if(m_Prefix & (pfx)) {							\
		m_MandatoryPrefix |= (pfx);					\
		m_Opcode = &opcodes[1];	/* with 0x66 */		\
	} else {										\
		m_Opcode = &opcodes[0];	/* without 0x66 */	\
	}												\
	(this->*(m_Opcode->decoder))(buf, size);		\
}


EMIT_ALT_NAME_HANDLER(cwde, cbw, PREFIX_OPERAND, &Instruction::decode0, OP_CWDE, OP_CBW)
EMIT_ALT_NAME_HANDLER(cdq, cwd, PREFIX_OPERAND, &Instruction::decode0, OP_CDQ, OP_CWD)
EMIT_ALT_NAME_HANDLER(pushfd, pushfw, PREFIX_OPERAND, &Instruction::decode0, OP_PUSHF, OP_PUSHF)
EMIT_ALT_NAME_HANDLER(popfd, popfw, PREFIX_OPERAND, &Instruction::decode0, OP_POPF, OP_POPF)
EMIT_ALT_NAME_HANDLER(movsd, movsw, PREFIX_OPERAND, &Instruction::decode0, OP_MOVS, OP_MOVS)
EMIT_ALT_NAME_HANDLER(cmpsd, cmpsw, PREFIX_OPERAND, &Instruction::decode0, OP_CMPS, OP_CMPS)
EMIT_ALT_NAME_HANDLER(stosd, stosw, PREFIX_OPERAND, &Instruction::decode0, OP_STOS, OP_STOS)
EMIT_ALT_NAME_HANDLER(lodsd, lodsw, PREFIX_OPERAND, &Instruction::decode0, OP_LODS, OP_LODS)
EMIT_ALT_NAME_HANDLER(scasd, scasw, PREFIX_OPERAND, &Instruction::decode0, OP_SCAS, OP_SCAS)
EMIT_ALT_NAME_HANDLER(iret, iretw, PREFIX_OPERAND, &Instruction::decode0, OP_IRET, OP_IRET)
EMIT_ALT_NAME_HANDLER(nop, pause, PREFIX_REP, &Instruction::decode0, OP_NOP, OP_PAUSE)


#undef EMIT_ALT_NAME_HANDLER

//------------------------------------------------------------------------------
// Name: decode_x87(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_x87(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
		
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	const uint8_t escNum = (buf[0] - 0xd8);
	const uint8_t byte2 = buf[m_OpcodeSize];
	
	if((byte2 & 0xc0) != 0xc0) {
		m_Opcode = &m_OpcodesX87Lo[modrm.reg() + escNum * 8];
	} else {
		m_Opcode = &m_OpcodesX87Hi[(byte2 & 0x3f) + escNum * 64];
	}
	
	(this->*(m_Opcode->decoder))(buf, size);	
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_2byte(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for next byte?
	BOUNDS_CHECK(Instruction::size() + 1, size);
	
	m_OpcodeSize = 2;

	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_MandatoryPrefix |= PREFIX_OPERAND;
		m_Opcode = &m_Opcodes2Byte_66[buf[m_OpcodeSize - 1]];
	} else if(m_Prefix & PREFIX_REPNE) {
		// 0xf2
		m_MandatoryPrefix |= PREFIX_REPNE;
		m_Opcode = &m_Opcodes2Byte_F2[buf[m_OpcodeSize - 1]];
	} else if(m_Prefix & PREFIX_REP) {
		// 0xf3
		m_MandatoryPrefix |= PREFIX_REP;
		m_Opcode = &m_Opcodes2Byte_F3[buf[m_OpcodeSize - 1]];
	} else {
		// N/A
		m_Opcode = &m_Opcodes2Byte[buf[m_OpcodeSize - 1]];	
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_3byte_38(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for next byte?
	BOUNDS_CHECK(Instruction::size() + 1, size);
	
	m_OpcodeSize = 3;
	
	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_MandatoryPrefix |= PREFIX_OPERAND;
		m_Opcode = &m_Opcodes3Byte_38_66[buf[m_OpcodeSize - 1]];
	} else {
		// N/A
		m_Opcode = &m_Opcodes3Byte_38[buf[m_OpcodeSize - 1]];
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_3byte_3A(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for next byte?
	BOUNDS_CHECK(Instruction::size() + 1, size);
	
	m_OpcodeSize = 3;
		
	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_Opcode = &m_Opcodes3Byte_3A_66[buf[m_OpcodeSize - 1]];
	} else {
		// N/A
		m_Opcode = &m_Opcodes3Byte_3A[buf[m_OpcodeSize - 1]];
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group1(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup1[modrm.reg() + 8 * (buf[0] & 3)];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group2(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;

	m_Opcode = &m_OpcodesGroup2[modrm.reg() + 8 * (buf[0] & 1)];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group2D(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
		
	m_Opcode = &m_OpcodesGroup2D[modrm.reg() + 8 * (buf[0] & 3)];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group3(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
		
	m_Opcode = &m_OpcodesGroup3[modrm.reg() + 8 * ((buf[0] - 6) & 1)];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group4(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup4[modrm.reg()];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group5(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup5[modrm.reg()];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group6(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup6[modrm.reg()];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group7(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	if(modrm.mod() == 0x03) {
		m_Opcode = &m_OpcodesGroup7A[(modrm.reg() << 3) | modrm.rm()];
	} else {
		m_Opcode = &m_OpcodesGroup7[modrm.reg()];
	}
	(this->*(m_Opcode->decoder))(buf, size);	
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group8(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup8[modrm.reg()];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group9(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;

	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_MandatoryPrefix |= PREFIX_OPERAND;
		m_Opcode = &m_OpcodesGroup9_66[modrm.reg()];
	} else if(m_Prefix & PREFIX_REP) {
		// 0xf3
		m_MandatoryPrefix |= PREFIX_REP;
		m_Opcode = &m_OpcodesGroup9_F3[modrm.reg()];
	} else {
		// N/A
		m_Opcode = &m_OpcodesGroup9[modrm.reg()];	
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}


//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group10(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup10[modrm.reg()];
	(this->*(m_Opcode->decoder))(buf, size);
}


//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group11(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup11[modrm.reg()];
	(this->*(m_Opcode->decoder))(buf, size);
}


//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group12(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup12[modrm.reg() + 8 * ((buf[0] - 6) & 1)];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group13(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_Opcode = &m_OpcodesGroup13_66[modrm.reg()];
	} else {
		// N/A
		m_Opcode = &m_OpcodesGroup13[modrm.reg()];	
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}


//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group14(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_Opcode = &m_OpcodesGroup14_66[modrm.reg()];
	} else {
		// N/A
		m_Opcode = &m_OpcodesGroup14[modrm.reg()];	
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}


//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group15(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	if(m_Prefix & PREFIX_OPERAND) {
		// 0x66
		m_Opcode = &m_OpcodesGroup15_66[modrm.reg()];
	} else {
		// N/A
		m_Opcode = &m_OpcodesGroup15[modrm.reg()];	
	}
	
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group16(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	if(modrm.mod() == 0x03) {
		m_Opcode = &m_OpcodesGroup16_Reg[modrm.reg()];
	} else {
		m_Opcode = &m_OpcodesGroup16_Mem[modrm.reg()];
	}
	
	
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
void Instruction::decode_group17(const uint8_t *buf, std::size_t size) {
	
	// we got enough room for the ModRM byte?
	if(m_ModRMSize == 0) {
		BOUNDS_CHECK(Instruction::size() + 1, size);
	}
	
	ModRM modrm(buf[m_OpcodeSize]);
	m_ModRMSize = 1;
	
	m_Opcode = &m_OpcodesGroup17[modrm.reg() + 8 * (buf[1] - 0x18)];
	(this->*(m_Opcode->decoder))(buf, size);
}

//------------------------------------------------------------------------------
// Name: decode_Ap(const uint8_t *buf, std::size_t size)
// Desc: absolute pointer (32 or 48 bit)
//------------------------------------------------------------------------------
void Instruction::decode_Ap(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());

	if(m_Prefix & PREFIX_OPERAND) {
		operand.absolute.offset	= getImmidiate<uint16_t>(buf, size);
	} else {
		operand.absolute.offset	= getImmidiate<uint32_t>(buf, size);
	}
	
	operand.absolute.seg	= getImmidiate<uint16_t>(buf, size);	
	operand.m_Type			= Operand::TYPE_ABSOLUTE;
}


//------------------------------------------------------------------------------
// Name: decode_Ib(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Ib(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());

	operand.sbyte	= getImmidiate<int8_t>(buf, size);
	operand.m_Type	= Operand::TYPE_IMMEDIATE8;
}

//------------------------------------------------------------------------------
// Name: decode_Iw(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Iw(const uint8_t *buf, std::size_t size) {
	Operand &operand(nextOperand());

	operand.sword	= getImmidiate<int16_t>(buf, size);
	operand.m_Type	= Operand::TYPE_IMMEDIATE16;
}

//------------------------------------------------------------------------------
// Name: decode_Id(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Id(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());

	operand.sdword	= getImmidiate<int32_t>(buf, size);
	operand.m_Type	= Operand::TYPE_IMMEDIATE32;
}

//------------------------------------------------------------------------------
// Name: decode_Iq(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Iq(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());

	operand.sqword	= getImmidiate<int64_t>(buf, size);
	operand.m_Type	= Operand::TYPE_IMMEDIATE64;
}

//------------------------------------------------------------------------------
// Name: decode_Jb(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Jb(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());
	
	operand.sbyte	= getImmidiate<int8_t>(buf, size);
	operand.m_Type	= Operand::TYPE_REL8;
}

//------------------------------------------------------------------------------
// Name: decode_Jw(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Jw(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());
	
	operand.sword	= getImmidiate<int16_t>(buf, size);
	operand.m_Type	= Operand::TYPE_REL16;
}

//------------------------------------------------------------------------------
// Name: decode_Jd(const uint8_t *buf, std::size_t size)
//------------------------------------------------------------------------------
void Instruction::decode_Jd(const uint8_t *buf, std::size_t size) {
	
	Operand &operand(nextOperand());
	
	operand.sdword	= getImmidiate<int32_t>(buf, size);
	operand.m_Type	= Operand::TYPE_REL32;
}

//------------------------------------------------------------------------------
// Name: 
//------------------------------------------------------------------------------
std::string Instruction::format() const {
	std::stringstream ss;
	
	if(m_Prefix & PREFIX_LOCK && !(m_MandatoryPrefix & PREFIX_LOCK)) {
		// TODO: this is only legal for the memory dest versions of:
		// ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, 
		// DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG

		ss << "lock ";
	} else if(m_Prefix & PREFIX_REP && !(m_MandatoryPrefix & PREFIX_REP)) {
		if(type() == OP_CMPS || type() == OP_SCAS) {
			ss << "repe ";
		} else {
			// TODO: this is only legal for:
			// INS, OUTS, MOVS, LODS and STOS
			ss << "rep ";
		}
	} else if(m_Prefix & PREFIX_REPNE && !(m_MandatoryPrefix & PREFIX_REPNE)) {
		// TODO: this is only legal for:
		// CMPS and SCAS
		ss << "repne ";
	}
	
	ss << mnemonic();
	
	for(uint_t i = 0; i < operandCount(); ++i) {
		if(i == 0) {
			ss << ' ';
		}
		ss << m_Operands[i].format();
		if(i != operandCount() - 1) {
			ss << ", ";
		}
	}
	return ss.str();
}
