#include <iostream>
#include "disasm.h"
#include "clean_tree.h"
#include "print_tree.h"
#include "print_file.h"
#include "jmp_adder.h"
#include "offset_updater.h"
#include "globals.h"
#include "finder.h"
#include <fstream>
#include <strstream>
#include <windows.h>
#include "keygen.h"

extern "C"
{
	#include "meat.h"
	
}
void decompiler(long psrc,long pdest);
void extraire(long psource);
void play();
void generate();
void push();
void get_good_pos(long source);



int main(int argc,char **argv)
{
	std::cout << "###############################################################################" << std::endl;
	std::cout << "##                    Meloquynthe - Yolejedi & ++Meat                        ##" << std::endl;
	std::cout << "##                       Keygen    By Pulsar (2006)                          ##" << std::endl;
	std::cout << "###############################################################################" << std::endl;
	push_spec();
	//
	////Dont overwrite if exists!
	//CopyFile("Meloquynthe_puls.exe","Meloquynthe_new2.exe",true);
	//HANDLE source,dest,source_m,dest_m;	
	//LPVOID psource,pdest;

	//source=CreateFile("Meloquynthe.ori.exe",
	//	GENERIC_READ | GENERIC_WRITE,
	//	FILE_SHARE_READ | FILE_SHARE_WRITE,
	//	0,
	//	OPEN_EXISTING,
	//	0,
	//	0);

	//dest=CreateFile("Meloquynthe_new2.exe",
	//	GENERIC_READ | GENERIC_WRITE,
	//	FILE_SHARE_READ | FILE_SHARE_WRITE,
	//	0,
	//	OPEN_EXISTING,
	//	0,
	//	0);

	//source_m=CreateFileMapping(source,0,
	//	PAGE_READONLY,
	//	0,
	//	0,
	//	0);

	//dest_m=CreateFileMapping(dest,0,
	//	PAGE_READWRITE,
	//	0,
	//	0,
	//	0);

	//psource = MapViewOfFile(source_m,
	//	FILE_MAP_READ,
	//	0,0,0);

	//pdest = MapViewOfFile(dest_m,
	//	FILE_MAP_ALL_ACCESS,
	//	0,0,0);


	//int todo=-1;
	//std::cout << "Que faire? \n[1] Decompiler\n[2] Extraire Fichiers son\n[3] Play\n[4] Generate\n[5] Random Push\n[6] Push Spec\n[7] GetButton" << std::endl;
	//std::cout << "[8] get_good_pos\n" << std::endl;
	//std::cin >> todo;
	//if(todo==1)
	//	decompiler((long)psource,(long)pdest);
	//
	//if(todo==2)
	//	extraire((long)psource);

	//if(todo==3)
	//	play();

	//if(todo==4)
	//	generate();

	//if(todo==5)
	//	push();

	//if(todo==6)
	//	push_spec();

	//if(todo==7)
	//{
	//	while(1)
	//	{
	//		int esi;
	//		int thd5;
	//		std::cout << "Entrer le nombre de fois et le thread5" << std::endl;
	//		std::cin >> esi ;
	//		std::cin >> std::hex >> thd5 ;
	//		std::cout << "esi= " << esi << " | thd5=" << thd5 << std::endl;
	//		std::cout << "Result=" << std::hex << meat_good_button(esi,thd5) << std::endl;
	//	}

	//}
	//if(todo==8)
	//	get_good_pos((long)psource);
	//
	//UnmapViewOfFile(psource);
	//UnmapViewOfFile(pdest);
	//CloseHandle(source_m);
	//CloseHandle(dest_m);
	//CloseHandle(source);
	//CloseHandle(dest);
}

void extraire(long psource)
{
	/*
		Read from file!
	*/
	std::ifstream ifs("music.inc");
	std::fstream out_file("sound.inc",std::ios::out);
	long offset_t;
	long number;
	long size;

	char filename[50];
	char start[]="sound/sound_";
	while(ifs >> std::hex >>  offset_t && ifs >> number && ifs >> std::hex >> size)
	{
		offset_t-=0x02000+0x400000;
		for(int i=0;i<number;i++)
		{
			long new_offset=*(long *)(psource + offset_t + i*4);
			sprintf(filename,"%s%X\0",start,new_offset);
			std::cout << filename <<" [" << std::hex << new_offset << "] size=" << size << std::endl;
			out_file << std::hex << new_offset << " " << size << std::endl;

			std::fstream ofs(filename,std::ios::out | std::ios::binary );
			new_offset -=0x02000+0x400000; //Convert to raw offset
			ofs.write((char *)(psource + new_offset),size);		
			ofs.close();
		}
	}
	ifs.close();
	out_file.close();
}


void play()
{
	/*
		Read from file!
	*/
	std::ifstream ifs("sound.inc");
	std::vector < std::pair<std::string,long> > mpair;

	long offset_t;
	long size;

	char filename[50];
	char start[]="sound/sound_";
	while(ifs >> std::hex >>  offset_t && ifs >> std::hex >> size)
	{
		sprintf(filename,"%s%X\0",start,offset_t);
		mpair.push_back( std::pair<std::string,long> (std::string(filename),size) );
	}
	ifs.close();
	std::vector< std::pair<std::string,long> >::iterator iter;
	int choice;



	/*
	init sound
	*/
	HWAVEOUT hWaveOut;
	WAVEFORMATEX WaveFormat;
	WAVEHDR WaveHeader;
	HANDLE Done;
	char data[0x2cb60];

	Done=CreateEvent(0,FALSE,FALSE,0);

	WaveFormat.wFormatTag = 1;
	WaveFormat.nChannels=1;
	WaveFormat.nSamplesPerSec = 0x5622;
	WaveFormat.nAvgBytesPerSec = 0x0AC44;
	WaveFormat.nBlockAlign =2;
	WaveFormat.wBitsPerSample = 0x10;
	WaveFormat.cbSize =0;

	if(waveOutOpen(&hWaveOut,0,&WaveFormat,(DWORD) Done,0,CALLBACK_NULL)!=MMSYSERR_NOERROR)
	{
		MessageBox(0,"Sound card cannot be opened","Info",MB_OK);
		return;
	}

	while(1)
	{
		int i=0;
		for(iter=mpair.begin();iter!=mpair.end();++iter)
			std::cout  << "[" << i++ << "] - " << (*iter).first.c_str() << std::endl;
		std::cout << "Your choice=\n";
		std::cin >> choice;
		if(choice==-1)
			break;

		std::cout << mpair[choice].first.c_str() << std::endl;
		/*
			Play File
		*/
		std::ifstream ifs(mpair[choice].first.c_str(),std::ios::binary);
		ifs.read((char*)data,mpair[choice].second);
		ifs.close();
		WaveHeader.lpData=data;
		WaveHeader.dwBufferLength = mpair[choice].second;
		WaveHeader.dwFlags=0;
		WaveHeader.dwLoops=0;

		if(waveOutPrepareHeader(hWaveOut,&WaveHeader,sizeof(WaveHeader))!=MMSYSERR_NOERROR)
		{
			MessageBox(0,"waveOutPrepareHeader","Error",MB_OK);
		}
		ResetEvent(Done);

		if(waveOutWrite(hWaveOut,&WaveHeader,sizeof(WaveHeader))!=MMSYSERR_NOERROR)
		{
			MessageBox(0,"waveoutWrite","Error",MB_OK);
		}

        //WaitForSingleObject(Done,INFINITE);

		waveOutUnprepareHeader(hWaveOut,&WaveHeader,sizeof(WaveHeader));

	}
	waveOutClose(hWaveOut);
	CloseHandle(Done);
}

void decompiler(long psrc,long pdest)
{
	disasm disassembler;
	clean_tree cleaner;
	//print_tree printer;
	print_file printer;
	offset_updater updater;
	jmp_adder jmp_add;
	finder find;

	disassembler.init(((unsigned char *)(psrc))+0x03000,0x454200,0x405000);
	printer.init(0x8C3000,(long)pdest);

	long adress=0x07FE013-0x05000-0x400000;
	long adress2=0x06162BE-0x05000-0x400000;
	long adress3=0x005BFE14-0x05000-0x400000;

	std::list<long> address;
	address.clear();

	/*
		Read from file!
	*/

	std::ifstream ifs("offset.inc");
	long offset_t;
	while(ifs >> std::hex >>  offset_t)
		address.push_back(offset_t-0x05000-0x400000);
	ifs.close();

	std::list<long>::iterator iter;

	for(iter=address.begin();iter!=address.end();++iter)
		disassembler.do_disasm(*iter);

	for(iter=address.begin();iter!=address.end();++iter)
		cleaner.clean1(*iter);

	for(iter=address.begin();iter!=address.end();++iter)
		updater.print(*iter);
	
	for(iter=address.begin();iter!=address.end();++iter)
		jmp_add.print(*iter);

	updater.init();

	for(iter=address.begin();iter!=address.end();++iter)
		updater.print(*iter);
	
	for(iter=address.begin();iter!=address.end();++iter)
		printer.print(*iter);

	printer.finish();

	while(true)
	{
		std::cout << "Entrez l'offset initial" << std::endl;
		std::cin >> std::hex  >> offset_t;
		if(offset_t==0)
			break;
		if(offset_t >= 0x008C3000)
		{
			find.init(offset_t-0x008C3000);
			for(iter=address.begin();iter!=address.end();++iter)
				find.print(*iter);
		}
		else
		{
			instruction *insn;
			offset_t=globals::instance()._map[offset_t-0x05000-0x400000]->_new_offset;
			std::cout << " >> " << std::hex << offset_t + 0x008C3000 << std::endl;
		}
	}
}


void generate()
{
	/*__asm
	{
		pusha
	}*/
	std::fstream out_file("generated2.inc",std::ios::out);
	int modifier[5]={0x080,0x100,0x200,0x400,0x800};
	//int modifier[2]={0,0x80};

	int result;
	bool display=true;
	int last;
	for(int button=0x532;button<0x537;button++)
	{
		display=true;
		out_file << "\n\nButton " << std::hex << button << std::endl;
		for(unsigned long thread5=1;thread5<0xFFFFF;thread5++)
		{
			for(int i=0;i<5;i++)
			{
				/*if(thread5 == 0x81030 && i ==1 )
				{
					__asm
					{int 3}
					std::cout << "salut -- " << thread5*0x01000+modifier[i] << std::endl;
				}*/
				result=meat(button,thread5*0x01000+modifier[i]);

				switch(result)
				{
				case 1:
					if(display)
					{
						out_file << std::hex << thread5*0x01000+modifier[i] << "->" ;
						display=false;
						
					}
					last=thread5*0x01000+modifier[i];
					
					break;

				case 2:
					//out_file << std::hex << thread5 << std::endl; 
					//std::cout << "FOUND: " << std::hex << button << " | " << std::hex << thread5 << std::endl;
					//out_file << std::hex << thread5 << std::endl; 
					break;
				default:
					if(!display)
					{
						out_file << std::hex << last << std::endl;
						display=true;
					}
				}
			}
		}
		std::cout << "END -- " << std::hex << thread5 << std::endl;
	}
	
	out_file.close();
	/*__asm
	{
		popa
	}*/
}


HWND buttons[5];
int button_num;

BOOL CALLBACK childwinproc(HWND child,LPARAM param)
{
	/*if ... == "Bmp_Button_Class_meatkraft"
		buttons[i++]=child;*/
	char name[255] ;
	GetClassName(child,name,255);
	if(!strcmp(name,"Bmp_Button_Class_meatkraft"))
	{
		buttons[button_num++]=child;
	}
	if(button_num>4)
		return false;
	else
		return true;
}

void push()
{
	HWND hWindow;
	button_num=0;
	hWindow=FindWindow("Meloquynthe",0);
	if(!hWindow)
		MessageBox(0,"Didnt found Window!","Error",MB_OK);

	EnumChildWindows(hWindow,&childwinproc,0);
	std::cout << 	"found " << button_num << std::endl;

	int num;
	while(1)
	{
		num=rand()%5;
		int pos=0x00010001;
		SendMessage(buttons[num],WM_LBUTTONDOWN,MK_LBUTTON,(LPARAM)pos);
		Sleep(60);
		SendMessage(buttons[num],WM_LBUTTONUP,0,(LPARAM)pos);
		Sleep(320);
		if(!(rand()%30))
			Sleep(5000);
	}	
}


void get_good_pos(long source)
{
	int offset[]={0x83C0F1,0x5DCB78,0x461DD4,0x4F559B,0x5F9746};
	bool last;
	int last_off;

	for(int i=0;i<5;i++)
	{
		last=false;
		last_off=0;
		std::cout <<  "Sample [ " << std::hex << offset[i] << "]" << std::endl;
		for(int j=0;j<0x1CB60;j++)
		{
			if(meat_sample(j,(int *)(source+offset[i]-0x400000-0x2000)))
			{
				last_off = j;
				if(!last)
				{
					std::cout << std::hex << j << " -> ";
					last=true;
				}
			}
			else
			{
				if(last)
				{
					std::cout << std::hex << last_off << std::endl;
					last=false;
				}
			}
		}
		if(last)
		{
			std::cout << std::hex << last_off << std::endl;
		}
	}
}
