#include "clean_tree.h"
#include "globals.h"
#include "instruction.h"

clean_tree::clean_tree(void)
{
}

clean_tree::~clean_tree(void)
{
}

void clean_tree::clean1(long start)
{
	
	instruction *ins=globals::instance()._map[start];
	x86_insn_t * insn=ins->insn();

	instruction *ins_n,*ins_n2=0;
	x86_insn_t * insn_n=0;

	while(1)
	{
		if(!ins)
			break;
		if(ins->cleaned)
			 break;
		if(!ins->next_flow && !ins->next)
			break;

		ins_n=globals::instance()._map[ins->next_flow];
		ins_n2=globals::instance()._map[ins->next];

		/*
			Warning!
			controlflow near!!
		*/
		if(insn->group == insn_controlflow && 
			insn->operands[0].op.type == op_relative_near)
		{
			printf("##### \tWarning: operand near found!");
			char line[4096];
			x86_format_insn(insn, line, 4096, intel_syntax);
			printf("[%X] %s\n",insn->addr,line);

			if(insn->bytes[0]>=0x70 && insn->bytes[0] <=0x80)
			{
				// F2 -> 0F 82 || F5 -> 0F 85 ...
				insn->bytes[1]=insn->bytes[0] + 0x10;
				insn->bytes[0]=0x0F;
				insn->size=6;
			}
			else
			{
				if(insn->bytes[0]==0xEB)
				{
					insn->bytes[0]=0xE9;
					insn->size=5;
				}
				else
				{
					printf("DO ME!\n");
					exit(0);
				}
			}
		}
		
		/*
			Remove jx jnx
		*/
		if(insn->type == insn_jcc &&
			ins->next &&
			ins_n2 && 
			ins_n2->insn()->type == insn_jcc)
		{
			ins_n2->next=0;
			ins->next = ins_n2->next_flow;
		}
		
		/*
			Remove Jumps!
		*/
		if(ins->next_flow 
			&& ins_n && ins_n->insn()->type == insn_jmp)
		{
			ins->next_flow = ins_n->next_flow;
		}
		else
		if(ins->next 
			&& ins_n2 && ins_n2->insn()->type == insn_jmp)
		{
			ins->next = ins_n2->next_flow;
		}

		ins->cleaned=true;
        if(ins->next && ins->next_flow)
		{
			int todo=ins->next;
			//printf("ins->offset %X cleans %X\n",insn->addr,insn->addr + ins->next_flow - insn->offset);
			clean1(ins->next_flow);
			ins = globals::instance()._map[todo];
		}
		else
		{
			if(ins->next)
			{
				ins = globals::instance()._map[ins->next];
			}
			else
			{
				if(ins->next_flow)
				{
					ins = globals::instance()._map[ins->next_flow];
				}
			}
		}
		insn=ins->insn();
	}
}