#ifndef _COMMON_CODEGEN_HPP_
#define _COMMON_CODEGEN_HPP_
#include <common/stdio.hpp>
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_FILEMAP_HPP_
#include <common/filemap.hpp>
#endif
#ifndef _COMMON_PUREVIEWOFFILE_HPP_
#include <common/pview.hpp>
#endif
#ifndef _COMMON_GLOBALDATA_HPP_
#include <common/gdata.hpp>
#endif

#if defined(_MSC_VER)
#pragma warning(disable:4355)
#endif

class CodeGen : public FileMap, public PureViewOfFile
{
public:
	CodeGen(DWORD maxExtent=100000L);
	virtual ~CodeGen();
	void breakPoint(void);
  void nop(void);
	void pushDS(void);
	void popDS(void);
	void pushCS(void);
	void movEAXOFFSETDS(int dsOffset);
	void movOFFSETDSEAX(int dsOffset);
	void pushad(void);
	void popad(void);
	void pushOFFSETCS(int csOffset);
	void pushEAX(void);
  void pushECX(void);
	void pushEBP(void);
	void pushESP(void);
	void pushEDI(void);
	void pushESI(void);
  void push(int value);
	void popEBP(void);
  void popESP(void);
	void popESI(void);
	void popEDI(void);
	void popAX(void);
	void popEAX(void);
	void popEBX(void);
	void popECX(void);
  void pushEBX(void);
	void subEDI(BYTE byteCount);
	void subESP(BYTE byteCount);
	void movDHDL(void);
	void movEDIDX(void);
	void movAXCS(void);
  void movEAXEBX(void);
  void movEBXEAX(void);
	void movEBPESP(void);
  void movECXESI(void);
	void movECXEDI(void);
	void movESIEBP(BYTE stackIndex);
	void movEDIEBP(BYTE stackIndex);
	void movEAXEBP(BYTE stackIndex);
  void movEAXESP(BYTE stackIndex);
  void movEAXEBP(void);
  void movEAXESP(void);
	void movAXEBP(BYTE stackIndex);
	void movBXEBP(BYTE stackIndex);
	void movCXEBP(BYTE stackIndex);
	void movDXEBP(BYTE stackIndex);
	void movALESI(LONG sourceIndex);
	void movESIAL(LONG sourceIndex);
	void movDLESI(DWORD sourceIndex);
	void movEDIDX(LONG offset);
	void movEDIDL(LONG offset);
	void movEDIAL(LONG offset);
	void movEDIDL(void);
	void movCLEBP(BYTE stackIndex);
  void movOFFSETESI(BYTE offset,BYTE charByte);
	void movEAXOFFSETCS(int csOffset);
  void movECXOFFSETCS(int csOffset);
  void movEAXOFFSETSS(int offset);
  void movOFFSETSSEAX(int offset);
  void movEAXESPOFFSET(int offset);
	void movEAXEBPOFFSET(int offset);
  void movESPOFFSETEAX(int offset);
  void movESPOFFSETEBX(int offset);
  void movDEREFEAXEBX(void);
  void leaESIEBP(BYTE offset);
	void addEDIEAX(void);
	void addEDIEBP(BYTE stackIndex);
	void addESP(int value);
	void addEAX(int value);
	void addEBP(int value);
	void subEAX(int value);
	void xorEAXEAX(void);
	void call(int offset);
	void callEBP(BYTE offset);
	void callEAX(void);
	void callEBX(void);
	void callECX(void);
	void je(BYTE jumpCount);
	void jmp(BYTE jumpBytes);
  void jnl(BYTE jumpCount);
	void cmpALCL(void);
	void decEDI(void);
	void movEAX(int value);
  void movECX(int value);
	void pushEBPEAXPLUS(int eaxAdditive);
	void decEAX(void);
	void cmpEAX(int value);
  void pushFSOFFSET(WORD offset);
  void movFSOFFSETESP(WORD offset);
  void movFSOFFSETEAX(int offset);
	void retn(void);
  void retn(short stackLength);
  void retf(void);
	void intno(BYTE intno);
	void encodeDD(int value=0);
  void encodeDB(BYTE value=0);
	void wait(void);
	void finit(void);
	void execute(void);
	void debugExecute(void);
private:
  String entryName(void)const;
};

inline
CodeGen::CodeGen(DWORD maxExtent)
: FileMap(entryName(),0L,1024), PureViewOfFile((FileMap&)*this)
{
}

inline
CodeGen::~CodeGen()
{
}

inline
void CodeGen::breakPoint(void)
{
  write((BYTE)(0xCC));
}

inline
void CodeGen::pushOFFSETCS(int csOffset)
{
	write((BYTE)(0x2E));
	write((BYTE)(0xFF));
	write((BYTE)(0x35));
  write(csOffset);
}

inline
void CodeGen::pushad(void)
{
	write((BYTE)(0x60));
}

inline
void CodeGen::popad(void)
{
	write((BYTE)(0x61));
}

inline
void CodeGen::pushEAX(void)
{
	write((BYTE)(0x50));
}

inline
void CodeGen::pushECX(void)
{
	write((BYTE)(0x51));
}

inline
void CodeGen::popECX(void)
{
	write((BYTE)(0x59));
}

inline
void CodeGen::pushEBP(void)
{
	write((BYTE)(0x55));
}

inline
void CodeGen::pushESP(void)
{
  write((BYTE)(0x54));
}

inline
void CodeGen::pushEDI(void)
{
	write((BYTE)(0x57));
}

inline
void CodeGen::pushESI(void)
{
	write((BYTE)(0x56));
}

inline
void CodeGen::popEBP(void)
{
	write((BYTE)(0x5D));
}

inline
void CodeGen::popESP(void)
{
  write((BYTE)(0x5C));
}

inline
void CodeGen::popESI(void)
{
	write((BYTE)(0x5E));
}

inline
void CodeGen::popEDI(void)
{
	write((BYTE)(0x5F));
}

inline
void CodeGen::popAX(void)
{
	write((BYTE)(0x66));
	write((BYTE)(0x58));
}

inline
void CodeGen::movEBPESP(void)
{
	write((BYTE)(0x8B));
	write((BYTE)(0xEC));
}

inline
void CodeGen::movESIEBP(BYTE stackIndex)
{
	write((BYTE)(0x8B));
	write((BYTE)(0x75));
	write(stackIndex);
}

inline
void CodeGen::movEDIEBP(BYTE stackIndex)
{
	write((BYTE)(0x8B));
	write((BYTE)(0x7D));
	write(stackIndex);
}

inline
void CodeGen::movEAXEBP(BYTE stackIndex)
{
	write((BYTE)(0x8B));
	write((BYTE)(0x45));
	write(stackIndex);
}

inline
void CodeGen::movEAXESP(BYTE stackIndex)
{
	write((BYTE)(0x8B));
	write((BYTE)(0x44));
	write((BYTE)(0x24));
	write(stackIndex);
}

inline
void CodeGen::movEAXEBP(void)
{
	write((BYTE)(0x8B));
	write((BYTE)(0xC5));
}

inline
void CodeGen::movEDIDL(void)
{
	write((BYTE)(0x88));
	write((BYTE)(0x17));
}

inline
void CodeGen::decEDI(void)
{
	write((BYTE)(0x4F));
}

inline
void CodeGen::addEDIEAX(void)
{
	write((BYTE)(0x03));
	write((BYTE)(0xF8));
}

inline
void CodeGen::addEDIEBP(BYTE stackIndex)
{
	write((BYTE)(0x03));
	write((BYTE)(0x7D));
	write(stackIndex);
}

inline
void CodeGen::retn(void)
{
	write((BYTE)(0xC3));
}

inline
void CodeGen::retn(short stackLength)
{
	write((BYTE)(0xC2));
  write(stackLength);
}

inline
void CodeGen::retf(void)
{
  write((BYTE)(0xCB));
}

inline
void CodeGen::movDLESI(DWORD sourceIndex)
{
	write((BYTE)(0x8A));
	write((BYTE)(0x96));
	write((BYTE)(sourceIndex&0x000000FF));
	write((BYTE)((sourceIndex&0x0000FF00)>>0x08));
	write((BYTE)((sourceIndex&0x00FF0000)>>0x10));
	write((BYTE)((sourceIndex&0xFF000000)>>0x18));
}

inline
void CodeGen::movDHDL(void)
{
	write((BYTE)(0x8A));
	write((BYTE)(0xF2));
}

inline
void CodeGen::movOFFSETESI(BYTE offset,BYTE charByte)
{
	write((BYTE)(0xC6));
	write((BYTE)(0x46));
	write(offset);
  write(charByte);
}

inline
void CodeGen::subEDI(BYTE byteCount)
{
	write((BYTE)(0x83));
	write((BYTE)(0xEF));
	write(byteCount);
}

inline
void CodeGen::subESP(BYTE byteCount)
{
	write((BYTE)(0x83));
	write((BYTE)(0xEC));
	write(byteCount);
}

inline
void CodeGen::movEDIDX(void)
{
	write((BYTE)(0x66));
	write((BYTE)(0x89));
	write((BYTE)(0x17));
}

inline
void CodeGen::movEDIDX(LONG sourceIndex)
{
	write((BYTE)(0x66));
	write((BYTE)(0x89));
	write((BYTE)(0x97));
	write((BYTE)(sourceIndex&0x000000FF));
	write((BYTE)((sourceIndex&0x0000FF00)>>0x08));
	write((BYTE)((sourceIndex&0x00FF0000)>>0x10));
	write((BYTE)((sourceIndex&0xFF000000)>>0x18));
}

inline
void CodeGen::movEDIDL(LONG sourceIndex)
{
	write((BYTE)(0x88));
	write((BYTE)(0x97));
	write((BYTE)(sourceIndex&0x000000FF));
	write((BYTE)((sourceIndex&0x0000FF00)>>0x08));
	write((BYTE)((sourceIndex&0x00FF0000)>>0x10));
	write((BYTE)((sourceIndex&0xFF000000)>>0x18));
}

inline
void CodeGen::movALESI(LONG sourceIndex)
{
	write((BYTE)(0x8A));
	write((BYTE)(0x86));
	write((BYTE)(sourceIndex&0x000000FF));
	write((BYTE)((sourceIndex&0x0000FF00)>>0x08));
	write((BYTE)((sourceIndex&0x00FF0000)>>0x10));
	write((BYTE)((sourceIndex&0xFF000000)>>0x18));
}

inline
void CodeGen::movESIAL(LONG sourceIndex)
{
	write((BYTE)(0x88));
	write((BYTE)(0x86));
	write((BYTE)(sourceIndex&0x000000FF));
	write((BYTE)((sourceIndex&0x0000FF00)>>0x08));
	write((BYTE)((sourceIndex&0x00FF0000)>>0x10));
	write((BYTE)((sourceIndex&0xFF000000)>>0x18));
}

inline
void CodeGen::movEDIAL(LONG sourceIndex)
{
	write((BYTE)(0x88));
	write((BYTE)(0x87));
	write((BYTE)(sourceIndex&0x000000FF));
	write((BYTE)((sourceIndex&0x0000FF00)>>0x08));
	write((BYTE)((sourceIndex&0x00FF0000)>>0x10));
	write((BYTE)((sourceIndex&0xFF000000)>>0x18));
}

inline
void CodeGen::movAXCS(void)
{
	write((BYTE)(0x66));
	write((BYTE)(0x8C));
	write((BYTE)(0xC8));
}

inline
void CodeGen::movCLEBP(BYTE stackIndex)
{
	write((BYTE)(0x8A));
	write((BYTE)(0x4D));
	write(stackIndex);
}

inline
void CodeGen::leaESIEBP(BYTE offset)
{
	write((BYTE)(0x8D));
	write((BYTE)(0x75));
  write(offset);
}

inline
void CodeGen::cmpALCL(void)
{
	write((BYTE)(0x3A));
	write((BYTE)(0xC1));
}

inline
void CodeGen::call(int offset)
{
	write((BYTE)(0xE8));
	write(offset);
}

inline
void CodeGen::callEBP(BYTE offset)
{
	write((BYTE)(0xFF));
	write((BYTE)(0x55));
	write(offset);
}

inline
void CodeGen::callEAX(void)
{
	write((BYTE)(0xFF));
	write((BYTE)(0xD0));
}

inline
void CodeGen::callEBX(void)
{
	write((BYTE)(0xFF));
	write((BYTE)(0xD3));
}

inline
void CodeGen::callECX(void)
{
	write((BYTE)(0xFF));
	write((BYTE)(0xD1));
}

inline
void CodeGen::je(BYTE jumpCount)
{
	write((BYTE)(0x74));
	write(jumpCount);
}

inline
void CodeGen::jmp(BYTE jumpCount)
{
	write((BYTE)(0xEB));
	write(jumpCount);
}

inline
void CodeGen::jnl(BYTE jumpCount)
{
	write((BYTE)(0x7D));
	write(jumpCount);
}

inline
void CodeGen::intno(BYTE intno)
{
	write((BYTE)(0xCD));
	write(intno);
}

inline
void CodeGen::movAXEBP(BYTE stackIndex)
{
	write((BYTE)(0x66));
	write((BYTE)(0x8B));
	write((BYTE)(0x45));
	write(stackIndex);
}

inline
void CodeGen::movBXEBP(BYTE stackIndex)
{
	write((BYTE)(0x66));
	write((BYTE)(0x8B));
	write((BYTE)(0x5D));
	write(stackIndex);
}

inline
void CodeGen::movCXEBP(BYTE stackIndex)
{
	write((BYTE)(0x66));
	write((BYTE)(0x8B));
	write((BYTE)(0x4D));
	write(stackIndex);
}

inline
void CodeGen::movDXEBP(BYTE stackIndex)
{
	write((BYTE)(0x66));
	write((BYTE)(0x8B));
	write((BYTE)(0x55));
	write(stackIndex);
}

inline
void CodeGen::xorEAXEAX(void)
{
	write((BYTE)(0x33));
	write((BYTE)(0xC0));
}

inline
void CodeGen::push(int value)
{
	write((BYTE)(0x68));
  write(value);
}

inline
void CodeGen::popEAX(void)
{
  write((BYTE)(0x58));
}

inline
void CodeGen::addESP(int value)
{
	write((BYTE)(0x81));
	write((BYTE)(0xC4));
  write(value);
}

inline
void CodeGen::addEAX(int value)
{
	write((BYTE)(0x05));
	write(value);
}

inline
void CodeGen::subEAX(int value)
{
	write((BYTE)(0x2D));
	write(value);
}

inline
void CodeGen::encodeDD(int value)
{
	write(value);
}

inline
void CodeGen::encodeDB(BYTE value)
{
  write(value);
}

inline
void CodeGen::execute(void)
{
	(*((FARPROC)((BYTE*)base())))();
}

inline
void CodeGen::debugExecute(void)
{
	GlobalData<BYTE> code;
	code.size(tell()+1);
	::memcpy((BYTE*)&code[0],(BYTE*)base(),tell()+1);
   (*((FARPROC)((BYTE*)&code[0])))();
}

inline
String CodeGen::entryName(void)const
{
	String entryPointName;
	::sprintf(entryPointName,"CODE%08lx.BIN",(DWORD)this);
	return entryPointName;
}

inline
void CodeGen::movEAXOFFSETCS(int csOffset)       // mov eax,cs:[csOffset]
{
	write((BYTE)(0x2E));
	write((BYTE)(0xA1));
	write(csOffset);
}

inline
void CodeGen::movECXOFFSETCS(int csOffset)       // mov ecx,cs:[csOffset]
{
  write((BYTE)(0x2E));
	write((BYTE)(0x8B));
	write((BYTE)(0x0D));
	write(csOffset);
}

inline
void CodeGen::pushDS(void)
{
  write((BYTE)(0x1E));
}

inline
void CodeGen::popDS(void)
{
  write((BYTE)(0x1F));
}

inline
void CodeGen::pushCS(void)
{
  write((BYTE)(0x0E));
}

inline
void CodeGen::movEAXOFFSETDS(int dsOffset)
{
	write((BYTE)(0xA1));
  write(dsOffset);
}

inline
void CodeGen::movOFFSETDSEAX(int dsOffset)
{
	write((BYTE)(0xA3));
	write(dsOffset);
}

inline
void CodeGen::nop(void)
{
  write((BYTE)(0x90));
}

inline
void CodeGen::movEAXEBX(void)      // mov eax,ebx
{
	write((BYTE)(0x8B));
	write((BYTE)(0xC3));
}

inline
void CodeGen::movEBXEAX(void)      // mov ebx,eax
{
  write((BYTE)(0x8B));
	write((BYTE)(0xD8));
}

inline
void CodeGen::popEBX(void)
{
	write((BYTE)(0x5B));
}

inline
void CodeGen::pushEBX(void)
{
	write((BYTE)(0x53));
}

inline
void CodeGen::movEAX(int value)
{
	write((BYTE)(0xB8));
	write(value);
}

inline
void CodeGen::pushEBPEAXPLUS(int eaxAdditive)
{
	write((BYTE)(0xFF));
	write((BYTE)(0xB4));
	write((BYTE)(0x05));
	write(eaxAdditive);
}

inline
void CodeGen::decEAX(void)
{
  write((BYTE)(0x48));
}

inline
void CodeGen::cmpEAX(int value)
{
	write((BYTE)(0x3D));
  write(value);
}

inline
void CodeGen::addEBP(int value)
{
	write((BYTE)(0x81));
	write((BYTE)(0xC5));
	write(value);
}

inline
void CodeGen::movECXESI(void)
{
  write((BYTE)(0x8B));
	write((BYTE)(0xCE));
}

inline
void CodeGen::movECXEDI(void)
{
  write((BYTE)(0x8B));
	write((BYTE)(0xCF));
}

inline
void CodeGen::movECX(int value)
{
  write((BYTE)(0xB9));
	write(value);
}

inline
void CodeGen::movEAXESP(void)
{
  write((BYTE)(0x8B));
	write((BYTE)(0xC4));
}

inline
void CodeGen::pushFSOFFSET(WORD offset)
{
  write((BYTE)(0x64));
	write((BYTE)(0x67));
	write((BYTE)(0xFF));
	write((BYTE)(0X36));
	write((BYTE)(offset&0x00FF));
	write((BYTE)(offset>>0x08));
}

inline
void CodeGen::movFSOFFSETESP(WORD offset)
{
  write((BYTE)(0x64));
	write((BYTE)(0x67));
	write((BYTE)(0x89));
	write((BYTE)(0x26));
	write((BYTE)(offset&0x00FF));
	write((BYTE)(offset>>0x08));
}

inline
void CodeGen::movEAXOFFSETSS(int offset)
{
  write((BYTE)(0x36));
	write((BYTE)(0xA1));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movOFFSETSSEAX(int offset)
{
  write((BYTE)(0x36));
	write((BYTE)(0xA3));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movEAXESPOFFSET(int offset)
{
  write((BYTE)(0x8B));
	write((BYTE)(0x84));
	write((BYTE)(0x24));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movEAXEBPOFFSET(int offset)
{
  write((BYTE)(0x8B));
	write((BYTE)(0x85));
	write((BYTE)(0x56));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movESPOFFSETEAX(int offset)
{
  write((BYTE)(0x89));
	write((BYTE)(0x84));
	write((BYTE)(0x24));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movFSOFFSETEAX(int offset)
{
  write((BYTE)(0x64));
	write((BYTE)(0xA3));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movESPOFFSETEBX(int offset)
{
  write((BYTE)(0x89));
  write((BYTE)(0x9C));
  write((BYTE)(0x24));
	write((BYTE)(offset));
	write((BYTE)(offset>>0x08));
	write((BYTE)(offset>>0x10));
	write((BYTE)(offset>>0x18));
}

inline
void CodeGen::movDEREFEAXEBX(void)
{
  write((BYTE)(0x89));
	write((BYTE)(0x18));
}

inline
void CodeGen::wait(void)
{
  write((BYTE)0x9B);
}

inline
void CodeGen::finit(void)
{
  write((BYTE)0xDB);
	write((BYTE)0xE3);
}
#endif
