#include <XBApp.h>
#include <XBFont.h>
#include <XBHelp.h>
#include <xgraphics.h>
#include <assert.h>
#include <d3d8perf.h>
#include "SndXBOX.hxx"
#include <stdio.h>
#include <vector>
#include "debugclient.h"


#ifdef __cplusplus
extern "C" {
#endif


#ifdef __cplusplus
}
#endif



#define PLATFORM_SAV L"BORXSAV"
#define READING_ROMS_STRING L"Reading borx directory...please wait."
#define PLATFORM_INI "borx.ini"
#define PLATFORM_MEMORY_POINTER NULL 
#define THEMEMUSIC "D:\\BORX\\THEME.MP3"
#define PLATFORM_FILE_DIR "D:\\borx\\*"
#define CONSOLE_MEMORY_SIZE 0xFF
#define DEFAULT_PARENT_DIR "D:\\borx\\"


//-----------------------------------------------------------------------------
// Name: class CXBoxSample
// Desc: Main class to run this application. Most functionality is inherited
//       from the CXBApplication base class.
//-----------------------------------------------------------------------------
class CXBoxSample : public CXBApplication
{
public:
    CXBoxSample();

    virtual HRESULT Initialize();
    virtual HRESULT InitializeWithScreen();
    virtual HRESULT Render();
    virtual HRESULT FrameMove();
	virtual void MoveCursor() ;
	virtual void    initConsole( UINT32 idx ) ;
	virtual void    cleanupConsole( ) ;
	virtual int     handleEvents() ;
	void            fillPresentationParams();
	virtual int     init_texture() ;
	virtual int		init_white_texture();
	virtual int		render_to_texture(int x, int y, int w, int h) ;
	virtual void	FindAvailRoms( char *parentdir) ;
	virtual void    doStartSearchMenu() ;
	virtual void    doCodeListMenu() ;
	virtual void    doAddFoundCodes() ;
	virtual void    doContinueSearchMenu() ;
	virtual void    doCheatMenu() ;
	virtual void    doEmulatorOptions() ;
	virtual void    doFontSize() ;
	virtual void    doSaveConfig() ;
	virtual void    doScreenSize() ;
	virtual void    doTextOffset() ;
	virtual void    doConfiguration() ;
	virtual void    updateCheats() ;
	virtual void    processEmu( BOOL render ) ;
	virtual void    cht_load() ;
	virtual void    cht_save() ;
	virtual void    deleteSaveFiles( int which ) ;
	virtual void    doEditCode( int which ) ;
	virtual BOOL    hasFiles( int which ) ;
	virtual int     rom_load_zip( char *hugozipfile ) ;
	virtual void    QuickSort( int start, int end ) ;
	void			MenuBar( int xpos, int ypos, int xlen, int ylen ) ;
	void            setPalette( unsigned int *palette) ;
	BOOL            SetRefreshRate(INT iRefreshRate);
	

	float fGameSelect;
	float fCursorPos;
	float m_fFrameTime ;
	float fMaxCount;
	int   iGameSelect;
	int   iCursorPos;
	UINT32 m_numFrames ;
	int   keyTime ;
	INT   m_nPitch ;
	int   m_p1Difficulty, m_p2Difficulty, m_p1Down, m_p2Down ;
	char    m_szCurrentDir[MAX_PATH] ;
	D3DPRESENT_PARAMETERS m_origPP ;


	UINT32 topIdx  ;
	UINT32 curr  ;
	CDebugClient m_debugClient ;
	D3DPalette			*m_pd3dPalette ;
	BOOL m_bAdjustMode ;

    CXBFont     m_Font;             // Font object
    CXBFont     m_FontSmall;             // Font object
    CXBHelp     m_Help;             // Help object
    BOOL        m_bDrawHelp;        // TRUE to draw help screen

    LPDIRECTSOUND8      m_pDSound;      // DirectSound object
    DWORD               m_dwCurrent;    // Current surface

	byte *m_memBuf1, *m_memBuf2, *m_consoleMemory, *m_memMatches ;
	UINT32 m_currentMemMatches ;

	typedef struct _filenamestruct {
		WCHAR name[200] ;
		unsigned char filename[200] ;
		char isDir ;
	} FILENAME ;

	FILENAME *files ;
	unsigned long numfiles ;
	UINT32   m_iMaxWindowList;
	UINT32   m_iWindowMiddle ;
	UINT32   m_steps ;
	DWORD    m_dwStartPause ;
	int		m_nbytes ;
	int		m_nXOffset, m_nFontHeight ;
	int		m_namesPerPage ;

	LPDIRECT3DTEXTURE8	Texture;
	LPDIRECT3DTEXTURE8	WhiteTexture;
	LPD3DXSPRITE			Sprite;
	LPD3DXSPRITE			MenuSprite;
	byte*				g_pBlitBuff ;
	byte*				g_pAlignBuff ;
	int					m_droppedFrames ;	
	
	UINT32				m_state ;
    WCHAR      m_strMessage[80];
	UINT32              m_msgDelay ;
	int                 m_msgtime ;


	SoundXBOX			m_sound;
	Mp3Player			m_mp3player;
	char				g_savePath[500] ;
	char				g_saveprefix[500] ;
	char				g_sramfile[500] ;
	char				g_bramfile[500] ;
	char				g_scrfile[500] ;
	char				g_cuefile[500] ;
	char				g_rtcfile[500] ;
	char				g_chtfile[500] ;
	char				g_statefile[500] ;
	FILE                *m_logfile ;

// Indicates the width and height of the screen
	UINT32 theWidth;
	UINT32 theHeight;
    RECT SrcRect;
    RECT DestRect;

	int					m_nScreenX, m_nScreenY, m_nScreenMaxX, m_nScreenMaxY ;

	typedef struct _cheat_code {
		char code[20] ;
		UINT32 adr ;
		UINT32 val ;
		byte   enabled ;
	} CHEAT_CODE;

	CHEAT_CODE *m_cheatCodes;

	UINT32 m_numCheats ;


};


//#include "..\common\commonfuncs.cpp"




int CXBoxSample::init_texture()
{
	// Release any previous texture
	if (Texture) 
	{ 
		Texture->Release();
		Texture = NULL;
	}
	
	theWidth = 320 ;
	theHeight = 240 ;

	// Create the texture
	D3DXCreateTexture(m_pd3dDevice, theWidth, theHeight, 0, 0, D3DFMT_P8, D3DPOOL_DEFAULT, &Texture);
	
	D3DSURFACE_DESC desc;
    Texture->GetLevelDesc(0, &desc);

	if (g_pBlitBuff != NULL)
	{
		delete [] g_pBlitBuff;
		g_pBlitBuff = NULL;
	}
	
	// Allocate a buffer to blit our frames to
	g_pBlitBuff = new byte[desc.Size];


	if (g_pAlignBuff != NULL)
	{
		delete [] g_pAlignBuff;
		g_pAlignBuff = NULL;
	}
	
	// Allocate a buffer to blit our frames to
	g_pAlignBuff = new byte[desc.Size];


	


	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = theHeight-1 ;
	rectSource.right  = theWidth-1 ;

	D3DLOCKED_RECT d3dlr;
	Texture->LockRect(0, &d3dlr, &rectSource, 0);


	m_nPitch = d3dlr.Pitch ;

	// Unlock our texture
	Texture->UnlockRect(0);

	m_pd3dDevice->CreatePalette( D3DPALETTE_256 , &m_pd3dPalette ) ;


	return 0;
}




void CXBoxSample::setPalette( unsigned int *palette)
{
	D3DCOLOR			*color_palette;

	m_pd3dPalette->Lock( &color_palette, 0 ) ;

	memset( color_palette, 0, 256*sizeof(D3DCOLOR) ) ;



	for (int i = 0; i < 128; i++)
	{
		color_palette[i] = palette[i] ;
	}

	m_pd3dPalette->Unlock() ;

	m_pd3dDevice->SetPalette( 0, m_pd3dPalette ) ;
}





void CXBoxSample::doEmulatorOptions()
{
}


void CXBoxSample::doCheatMenu()
{

	while ( 1 )
	{
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		m_Font.Begin();
		m_Font.DrawText( (float)m_nXOffset+  32, 16*2, 0xffffffff, L"OPTIONS MENU" );
		m_Font.DrawText( (float)m_nXOffset+  32, 16*4, 0xffffffff, L"B - Return to Game" );
		m_Font.DrawText( (float)m_nXOffset+  32, 16*5, 0xffffffff, L"START+BACK - Quit Game" );


		m_Font.End();

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

        XBInput_GetInput();
		if(g_Gamepads[0].hDevice && g_Gamepads[0].bPressedAnalogButtons[XINPUT_GAMEPAD_B])
		{
			m_sound.pause( FALSE ) ;
			m_mp3player.pause( FALSE ) ;
			m_state = IN_GAME ;
			break ;
		}
		else if ( ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_START )  &&
			      ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_BACK )  )
		{
			m_sound.cleanup() ;
			m_mp3player.cleanup() ;
			cleanupConsole() ;
			m_state = MAIN_MENU ;
			break ;
		}


	}

}


//-----------------------------------------------------------------------------
// Name: FrameMove
// Desc: Performs per-frame updates
//-----------------------------------------------------------------------------
HRESULT CXBoxSample::FrameMove()
{

	m_bPaused =  ( m_state != IN_GAME ) ;


	if ( m_state == IN_GAME )
	{
		if ( m_dwStartPause > 0 )
		{
			g_dwTimePaused += ( GetTickCount() - m_dwStartPause ) ;
			m_dwStartPause = 0;
		}

		if(m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			m_sound.pause( TRUE ) ;
			m_mp3player.pause( TRUE ) ;
			m_state = IN_GAME_PAUSED ;
			m_dwStartPause = GetTickCount();
			return S_OK ;
		}
	}
	else if ( m_state == MAIN_MENU )
	{
		m_mp3player.process() ;

		if(m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y])
		{
		}
		else if ( ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_START )  &&
			      ( g_Gamepads[0].hDevice && g_Gamepads[0].wButtons & XINPUT_GAMEPAD_BACK )  &&
				  ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]) &&
				  ( g_Gamepads[0].hDevice && g_Gamepads[0].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) )
		{
			LD_LAUNCH_DASHBOARD LaunchData = { XLD_LAUNCH_DASHBOARD_MAIN_MENU };
			XLaunchNewImage( NULL, (LAUNCH_DATA*)&LaunchData );
		}
		else if ( (m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_X]) && (m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_B]) )
		{
			m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
								 0x00000000, 1.0f, 0L );
			RenderGradientBackground( 0xFF000000, 0xFF000000 );
			m_Font.Begin();
			m_Font.DrawText( (float)m_nXOffset+  32, 16*2, 0xffffffff, L"Reloading game list..." ) ;
			m_Font.End();
			m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

			if ( numfiles > 0 )
			{
				delete [] files;
				files = NULL;
			}

			numfiles = 0 ;

			char tmpdir[MAX_PATH] ;
			sprintf( tmpdir, "%s*", m_szCurrentDir ) ;

			FindAvailRoms(tmpdir) ;
			curr = 0 ;
			topIdx = 0 ;

		}
		else
		{
			// check for cursor select movement and move
			MoveCursor();

			// check for selection of game and do something (anything!)
			if(m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_A])
			{
				if ( files[curr].isDir )
				{
					numfiles = 0 ;

					char tmpdir[MAX_PATH] ;
					char *p ;

					if ( curr )
						sprintf( tmpdir, "%s%s\\*", m_szCurrentDir, (char*)files[curr].filename ) ;
					else
					{
						strcpy( tmpdir, m_szCurrentDir ) ;

						p = strrchr( tmpdir, '\\' ) ;
						if ( p )
							*p = 0 ;
						p = strrchr( tmpdir, '\\' ) ;
						if ( p )
							*p = 0 ;
						strcat( tmpdir, "\\*" ) ;
					}

					FindAvailRoms( tmpdir ) ;
					curr = 0 ;
					topIdx = 0 ;
				}
				else
				{
					m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
										 0x00000000, 1.0f, 0L );
					RenderGradientBackground( 0xFF000000, 0xFF000000 );
					m_Font.Begin();
					m_Font.DrawText( (float)m_nXOffset+  32, 16*2, 0xffffffff, L"Loading game...please wait." ) ;
					m_Font.End();
					m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
					m_state = IN_GAME ;
					initConsole(curr) ;
				}
				return S_OK ;
			}
			else if(m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_LEFT_THUMB )
			{
				doConfiguration() ;
				return S_OK ;
			}
		}
	}
	else if ( m_state == IN_GAME_PAUSED )
	{
		m_sound.pause( TRUE ) ;
		m_mp3player.pause( TRUE ) ;
		m_bPaused =  TRUE ;
		doCheatMenu() ;

		if ( m_state == MAIN_MENU )
		{
		}

		return S_OK ;
	}
	else
	{
	}

    return S_OK;
}


int CXBoxSample::render_to_texture(int x, int y, int w, int h)
{

	//DOXXX
	RECT src, dst;
	byte *curr1, *curr2 ;
	char xmsg[100] ;
	FILE *outfile ;

	//outfile = fopen(g_scrfile, "wb") ;
	//fwrite( ScreenBuffer, sizeof(char), 65000, outfile ) ;
	//fclose(outfile) ;

	
	//sprintf( xmsg, "x=%u,y=%u,w=%u,h=%u\r\n", x, y, w, h ) ;
	//writexbox(xmsg) ;

	// Get a description of our level 0 texture so we can figure
	// out the pitch of the texture
	D3DSURFACE_DESC desc;
    Texture->GetLevelDesc(0, &desc);
	
	theHeight = MaxLines ;
	theWidth = 320 ;

	// Allocate a buffer to blit our frames to

	// Figure out how big of a rect to lock in our texture
	RECT rectSource;
	rectSource.top = 0;
	rectSource.left = 0;
	rectSource.bottom = theHeight - 1 ;
	rectSource.right  = theWidth  - 1;

	// Lock the rect in our texture
	D3DLOCKED_RECT d3dlr;
	Texture->LockRect(0, &d3dlr, &rectSource, 0);

	//sprintf(xmsg, "h=%u,w=%u\r\n", io.screen_h, io.screen_w) ;
	//writexbox( xmsg) ;

	curr1 = g_pBlitBuff ;
	//DOXXX
	curr2 = NULL ;

//	for ( unsigned int y = 0 ; y < theHeight ; y++ )
	//{
		//curr1 = ((byte*)g_pBlitBuff) + ( y*d3dlr.Pitch ) ;
		//curr2 = ((byte*)osd_gfx_buffer) + ( y*(320+64+40) ) + ( ( (320+64+40)-io.screen_w ) /2 )  ;
		//memcpy( curr1, curr2, io.screen_w ) ;
	//}
	
	// Swizzle the blittled surface back to the texture
	XGSwizzleRect(g_pBlitBuff, 0, NULL, d3dlr.pBits, desc.Width, desc.Height, NULL, 1);


	// Swizzle the blittled surface back to the texture
//	XGSwizzleRect(osd_gfx_buffer2, 0, NULL, d3dlr.pBits, desc.Width, desc.Height, NULL, 2);

	// Unlock our texture
	Texture->UnlockRect(0);

	//delete [] g_pBlitBuff;
	//g_pBlitBuff = NULL;



	src.left   = 0;
	src.top    = 0;
	src.right  = theWidth  + 0;
	src.bottom = theHeight + 1;

	UINT iWidth  = theWidth;
	UINT iHeight = theHeight;
	
	// win_start_maximized the rect, constraining to the aspect ratio
	dst.left   = dst.top = 0;
	dst.right  = iWidth;
	dst.bottom = iHeight;
	
	// center
	//dst.left   += ((iWidth - (dst.right - dst.left)) / 2)  + ((640-iWidth)/2);
	//dst.top    += ((iHeight - (dst.bottom - dst.top)) / 2) + ((480-iHeight)/2);
	//dst.right  += dst.left;
	//dst.bottom += dst.top;
	
    // Clear the viewport
//	if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_A ] ) || ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_X ] ) )  
	    g_pd3dDevice->Clear(0L, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0L);
	
	// Begin the Scene
	g_pd3dDevice->BeginScene();

	// Compute the source and dest image sizes
	const float dw = (float)dst.right-dst.left;
	const float dh = (float)dst.bottom-dst.top;
	const float sw = (float)src.right-src.left;
	const float sh = (float)src.bottom-src.top;
	float mx, my ;

	y = y + 10 ;
	h += 6 ;

	//rectSource.top = y;
	//rectSource.left = x;
	//rectSource.bottom = h+y ;
	//rectSource.right  = w+x ;

	//160 = pixels width, 266 = max scan lines height
//xbox_put_image(Real_Horiz, Vert, Real_width, height-2*Vert) ;
//40,20,320,260
//x, y, w,   h

	mx = (float)m_nScreenMaxX / (float) (theWidth) ;
	my = (float)m_nScreenMaxY / (float) (theHeight) ;

	//mx = 1 ;
	//my = 1 ;

	// Compute the scale and transform vectors
	//D3DXVECTOR2 vecScale(dw/sw, dh/sh);
	D3DXVECTOR2 vecScale(mx, my);
	D3DXVECTOR2 vecTranslate((float)m_nScreenX, (float)m_nScreenY );


	//mx = 640.0f / io.screen_w ;
	//my = 480.0f / io.screen_h ;
	//mx = 580.0f / io.screen_w ;
	//my = 400.0f / io.screen_h ;



	// Compute the scale and transform vectors
	//D3DXVECTOR2 vecScale(dw/sw, dh/sh);
	//D3DXVECTOR2 vecScale( mx,my ) ;
	//D3DXVECTOR2 vecScale( min(mx,my), min(mx,my) ) ;
	//D3DXVECTOR2 vecScale( (io.screen_w <= 320) ? 2 : 1 , (io.screen_w <= 320) ? 2 : 1);
	//D3DXVECTOR2 vecTranslate( 10, 20 ) ;
	//D3DXVECTOR2 vecTranslate( ( 640.0f - ( (float)io.screen_w * ( min(mx,my) ) ) )/2,
		                      //( 480.0f - ( (float)io.screen_h * ( min(mx,my) ) ) )/2 );
	//D3DXVECTOR2 vecTranslate( ( 640.0f - ( (float)io.screen_w * ( mx ) ) )/2,
		                      //( 480.0f - ( (float)io.screen_h * ( my ) ) )/2 );
	//D3DXVECTOR2 vecTranslate( (io.screen_w <= 320) ? 320 - io.screen_w : 320 - ( io.screen_w/2), 
	//	                      (io.screen_w <= 320) ? 240 - io.screen_h : 240 - ( io.screen_h/2)  );
	//D3DXVECTOR2 vecTranslate(dst.left, dst.top);
	
	D3DXCOLOR d3color(1.0, 1.0, 1.0, 1.0);
	
	// Draw the sprite
	//if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_A ] ) || ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_Y ] ) )  
		Sprite->Draw(Texture, &rectSource, &vecScale, NULL, 0, &vecTranslate, d3color);

	if ( m_bAdjustMode )
	{
		m_Font.Begin();
		m_Font.DrawText( (float)m_nXOffset+  64, 64, 0xffffffff, L"Screen Adjust Mode" );
		m_Font.End();

	}
		
	if ( m_msgtime )
	{
		m_msgtime-- ;

		m_Font.Begin();
		m_Font.DrawText( (float)m_nXOffset+  64, 80, 0xffffffff, m_strMessage );
		m_Font.End();

	}
	// End the scene.
	g_pd3dDevice->EndScene();
	
	// Present the scene
	//if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_A ] ) || ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_BLACK ] ) )  
		g_pd3dDevice->Present(NULL, NULL, NULL, NULL);

	return 1;
}



//-----------------------------------------------------------------------------
// Name: Render
// Desc: Renders the scene
//-----------------------------------------------------------------------------
HRESULT CXBoxSample::Render()
{
	m_bPaused =  ( m_state != IN_GAME ) ;


	if ( m_state == IN_GAME )
	{
		if ( m_dwStartPause > 0 )
		{
			g_dwTimePaused += ( GetTickCount() - m_dwStartPause ) ;
			m_dwStartPause = 0;
		}

		// Clear the zbuffer
		//m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 //0x00000000, 1.0f, 0L );

		// Draw a gradient filled background
		//RenderGradientBackground( 0xff404040, 0xff404080 );

		if ( global_error_message[0] != 0 )
		{

			m_Font.Begin();
			//swprintf( str, L"%S", global_error_message );
			//m_Font.DrawText( 32, 48, 0x40ffffff, str );
			m_Font.DrawText( (float)m_nXOffset+ 32, 48, 0xffffffff, L"ERROR" );
			m_Font.End();
		}
		else
		{

			processEmu( TRUE ) ;

			if ( m_msgDelay > 0 )
			{
				m_msgDelay-- ;
				m_Font.Begin();
				m_Font.DrawText( (float)m_nXOffset+  32, 32, 0xffffff00, m_strMessage );
				m_Font.End();
			}
			else
			{
				//float elapsedTime ;
				//m_Font.Begin();
				//WCHAR str[2000];
				//swprintf( str, L"width = %u, height = %u", io.screen_w, io.screen_h ) ;
				//elapsedTime = ( (float)GetTickCount() - (float)g_dwStartTime - (float)g_dwTimePaused ) / 1000.0f ;
				//swprintf( str, L"numbytes apptime %5.5f, sndbytes %u, avg %6.5f, fps %5.5f cfps %5.5f", elapsedTime, m_sound.m_totalBytesWritten, 
					//((float)m_sound.m_totalBytesWritten) / elapsedTime, m_fFPS, ((float)m_numFrames) / m_fAppTime );
				//m_Font.DrawText( 30, 320, 0xFFffffff, str );
				//m_Font.End();
			}
		}
		
		// Present the scene
		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
	}
	else if ( m_state == IN_GAME_PAUSED )
	{
	}
	else if ( m_state == MAIN_MENU )
	{
		// Clear the zbuffer
		m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
							 0x00000000, 1.0f, 0L );
		RenderGradientBackground( 0xFF000000, 0xFF000000 );

		if(m_DefaultGamepad.bAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			m_Font.Begin(); 
			m_Font.DrawText( (float)m_nXOffset+32, 16*3,  0xffffffff, L"Z26 for XBOX");
			m_Font.DrawText( (float)m_nXOffset+32, 16*5,  0xffffffff, L"Main Menu Controls");
			m_Font.DrawText( (float)m_nXOffset+32, 16*6,  0xffffffff, L"A - Play Selected Game");
			m_Font.DrawText( (float)m_nXOffset+32, 16*7,  0xffffffff, L"Y - Show This Help Screen");
			m_Font.DrawText( (float)m_nXOffset+32, 16*8,  0xffffffff, L"UP/DOWN - Select Game");
			m_Font.DrawText( (float)m_nXOffset+32, 16*9,  0xffffffff, L"RIGHT/LEFT - Next/Prev Page");
			m_Font.DrawText( (float)m_nXOffset+32, 16*10,  0xffffffff, L"LS/RS - Next/Prev Letter");
			m_Font.DrawText( (float)m_nXOffset+32, 16*11,  0xffffffff, L"START+BACK+LS+RS - Exit to dashboard");
			m_Font.DrawText( (float)m_nXOffset+32, 16*12,  0xffffffff, L"X+B - Reload list");
			m_Font.DrawText( (float)m_nXOffset+32, 16*13,  0xff00ff00, L"Lines colored like this have save files on the HD.");

			m_Font.DrawText( (float)m_nXOffset+32, 16*15, 0xffffffff, L"In-Game Controls");
			m_Font.DrawText( (float)m_nXOffset+32, 16*16, 0xffffffff, L"A - Fire Button");
			m_Font.DrawText( (float)m_nXOffset+32, 16*17, 0xffffffff, L"X - Booster Grip Trigger");
			m_Font.DrawText( (float)m_nXOffset+32, 16*18, 0xffffffff, L"B - Booster Grip Booster");
			m_Font.DrawText( (float)m_nXOffset+32, 16*19, 0xffffffff, L"DPAD - Joystick Movement");
			m_Font.DrawText( (float)m_nXOffset+32, 16*20, 0xffffffff, L"LTHUMB - Paddle Movement");
			m_Font.DrawText( (float)m_nXOffset+32, 16*21, 0xffffffff, L"START - Reset");
			m_Font.DrawText( (float)m_nXOffset+32, 16*22, 0xffffffff, L"BACK - Select");
			m_Font.DrawText( (float)m_nXOffset+32, 16*23, 0xffffffff, L"Y - Options Menu");
			m_Font.DrawText( (float)m_nXOffset+32, 16*24, 0xffffffff, L"L/RTRIGGER - Difficulty Switches");
			m_Font.DrawText( (float)m_nXOffset+32, 16*25, 0xffffffff, L"WHITE/BLACK - Paddle Sensitivity");
			m_Font.DrawText( (float)m_nXOffset+32, 16*26, 0xffffffff, L"LTHUMB - Press to adjust screen size/pos");
			m_Font.End();
		}
		else if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_BLACK ] ) &&
				  ( m_DefaultGamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ) &&
				  ( m_DefaultGamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ) )
		{
			m_Font.Begin(); 
			m_Font.DrawText( (float)m_nXOffset+48, 32, 0xffffffff, L"Z26 for XBOX - made by me");
			m_Font.End();
		}
		else if ( ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_BLACK ] ) &&
				  ( m_DefaultGamepad.bAnalogButtons[ XINPUT_GAMEPAD_WHITE ] ) )
		{
			deleteSaveFiles( curr ) ;
		}
		else
		{
			WCHAR str[2000];
			swprintf( str, L"Z26 for XBOX  Y-Help Screen  Found %u games", numfiles);

			m_Font.Begin(); 
			m_FontSmall.Begin(); 
			m_Font.DrawText( (float)m_nXOffset+ 48, 32, 0xffffffff, str );
			//m_Font.DrawText(48, 32, 0x40ffffff, L"Gnuboy for XBOX  Y-Help Screen");


			
			
			float fWinX = 32, fWinY = 64;

			MenuBar( m_nXOffset+(int)fWinX, (int)fWinY+ (( m_nFontHeight+2)*(curr-topIdx)) + 3, 600, m_nFontHeight+3 ) ;

			for ( unsigned int idx = topIdx ; ( idx < numfiles ) && ( idx < topIdx+m_namesPerPage) ; idx++ )
			{
				if ( curr == idx )
				{
					if ( hasFiles( idx ) )
						m_FontSmall.DrawText( (float)m_nXOffset+fWinX  , fWinY, 0xffff00ff, files[idx].name );
					else
						m_FontSmall.DrawText( (float)m_nXOffset+fWinX , fWinY, 0xff000000, files[idx].name );
				}
				else
				{
					if ( hasFiles( idx ) )
						m_FontSmall.DrawText( (float)m_nXOffset+fWinX, fWinY, 0xff00ff00, files[idx].name );
					else
						m_FontSmall.DrawText( (float)m_nXOffset+fWinX, fWinY, 0xffffffff, files[idx].name );
				}
				fWinY += (m_nFontHeight + 2);
			}
			

			// end font drawing
			m_Font.End();
			m_FontSmall.End();


		}

		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
	}
	else if ( m_state == INIT_SYSTEM )
	{
		InitializeWithScreen() ;
	}
	else if ( m_state == INIT_SYSTEM_SHOW_SCREEN )
	{
	}
	else
	{
	}



    return S_OK;
}

/**
  This routine should be called regularly to handle events
*/

int CXBoxSample::handleEvents()
{
	char xmsg[100] ;
	int x, y, maxx, maxy ;
	static float fx = m_nScreenX ;
	static float fy = m_nScreenY ;
	static float fmaxx = m_nScreenMaxX ;
	static float fmaxy = m_nScreenMaxY ;
	

#define QUIT_EMU			0x01		// ESC (Quit to DOS)

#define EMU_RESET			0x3B		//; F1  (Reset)
#define EMU_SELECT			0x3C		//; F2  (Select)
#define EMU_BW				0x3D		//; F3  (B/W)
#define EMU_COLOR			0x3E		//; F4  (Color)
#define EMU_P1EASY			0x3F		//; F5  (P0 easy)
#define EMU_P1HARD			0x40		//; F6  (P0 hard)
#define EMU_P2EASY			0x41		//; F7  (P1 easy)
#define EMU_P2HARD			0x42		//  F8  (P1 hard)


#define P1LEFT 		0x4B		//; p1 left
#define P1RIGHT		0x4D		//; p1 right
#define P1UP 		0x48		//; p1 up
#define P1DOWN 		0x50		//; p1 down
#define P1FIRE 		0x1d		//; p1 fire
#define P1BG_B 		0x36        //; p1 booster bg
#define P1BG_T 		0x35		//; p1 trigger bg

#define P2LEFT 			0x1f		//; S (P2 left)
#define P2RIGHT			0x21		//; F (P2 right)
#define P2UP 			0x12		//; E (P2 up)
#define P2DOWN 			0x20		//; D (P2 down)
#define P2FIRE 			0x31		//; N (P2 fire)
#define P2BG_T 			0x30		//; B (P2 booster grip - trigger)
#define P2BG_B 			0x2F		//; V (P2 booster grip - booster)


//Mouse Handling in Paddle emulation
//----------------------------------
//
   //Tab -- switch between  horiz. normal, vert. normal
                     //and  horiz. reversed, and vert reversed

			if ( m_state == MAIN_MENU )
			{
				return 1 ;
			}

	//updateCheats() ;

	XBInput_GetInput();

	for ( int i = 0 ; i < 2 ; i++ )
	{
		if(g_Gamepads[i].hDevice && g_Gamepads[i].bAnalogButtons[XINPUT_GAMEPAD_Y])
		{
			m_state = IN_GAME_PAUSED ;
			m_sound.pause( TRUE ) ;
			//m_mp3player.pause( TRUE ) ;
			m_dwStartPause = GetTickCount();
			doCheatMenu() ;

			if ( m_state == MAIN_MENU )
			{
				return 1 ;
			}
		}

		if ( g_Gamepads[i].hDevice && g_Gamepads[i].bPressedAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) 
		{
			if ( m_p1Difficulty )
				IOPortB &= 0xBF ;
			else
				IOPortB |= 0x40 ;

			m_p1Difficulty = ! m_p1Difficulty ;

			swprintf( m_strMessage, L"Player 1 Difficulty set to %S", !m_p1Difficulty ? "Easy" : "Hard" ) ;

			m_msgtime = 60 ;

		}

		if ( g_Gamepads[i].hDevice && g_Gamepads[i].bPressedAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]) 
		{
			if ( m_p2Difficulty )
				IOPortB &= 0x7f ;
			else
				IOPortB |= 0x80 ;

			m_p2Difficulty = ! m_p2Difficulty ;

			swprintf( m_strMessage, L"Player 2 Difficulty set to %S", !m_p2Difficulty ? "Easy" : "Hard" ) ;

			m_msgtime = 60 ;

		}

		if ( g_Gamepads[i].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE]) 
		{
			if ( PaddleGame )
			{
				PaddleGame++ ;
				swprintf( m_strMessage, L"Paddle sensitivity set to %u", PaddleGame ) ;
				m_msgtime = 60 ;
			}
		}
		else if ( g_Gamepads[i].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK]) 
		{
			if ( PaddleGame )
			{
				if ( PaddleGame>1)
					PaddleGame-- ;
				swprintf( m_strMessage, L"Paddle sensitivity set to %u", PaddleGame ) ;
				m_msgtime = 60 ;
			}
		}

		if( g_Gamepads[i].hDevice && g_Gamepads[i].wPressedButtons & XINPUT_GAMEPAD_LEFT_THUMB )
		{
			 m_bAdjustMode = !m_bAdjustMode ;
		}

		if ( m_bAdjustMode )
		{
			if ( g_Gamepads[i].hDevice )
			{
				fx += ( g_Gamepads[i].fX1 );
				fy -= (g_Gamepads[i].fY1 );
				fmaxx += (g_Gamepads[i].fX2 );
				fmaxy -= (g_Gamepads[i].fY2 );

				m_nScreenX = fx ;
				m_nScreenY = fy ;
				m_nScreenMaxX = fmaxx ;
				m_nScreenMaxY = fmaxy ;
			}
		}
		else
		{
			if ( i==0 )
				xbox_curr_x += ((float)PaddleGame)*(g_Gamepads[i].fX1 ) ;
			else
				xbox_curr_y += ((float)PaddleGame)*(g_Gamepads[i].fY1 ) ;

		}
	}


	if ( g_Gamepads[0].hDevice )
	{
		if ( g_Gamepads[0].bAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
		{
			KeyTable[P1FIRE] = 0x80 ;
			if ( PaddleGame )
				srv_mouse_button = 1 ;

		}
		else
		{
			KeyTable[P1FIRE] = 0 ;
			if ( PaddleGame )
				srv_mouse_button = 0 ;
		}

		if ( g_Gamepads[0].bAnalogButtons[ XINPUT_GAMEPAD_X ] ) 
			KeyTable[P1BG_B] = 0x80 ;
		else
			KeyTable[P1BG_B] = 0 ;

		if ( g_Gamepads[0].bAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
			KeyTable[P1BG_T] = 0x80 ;
		else
			KeyTable[P1BG_T] = 0 ;

		if ( g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
			KeyTable[P1LEFT] = 0x80 ;
		else
			KeyTable[P1LEFT] = 0 ;

		if ( g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_UP ) 
			KeyTable[P1UP] = 0x80 ;
		else
			KeyTable[P1UP] = 0 ;

		if ( g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
			KeyTable[P1RIGHT] = 0x80 ;
		else
			KeyTable[P1RIGHT] = 0 ;

		if ( g_Gamepads[0].wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
			KeyTable[P1DOWN] = 0x80 ;
		else
			KeyTable[P1DOWN] = 0 ;
			 
		if ( g_Gamepads[0].wButtons & XINPUT_GAMEPAD_START )  //reset
		{
			//KeyTable[EMU_RESET] = 0x80 ;
			IOPortB &= 0xFE ;
		}
		else
		{
			IOPortB |= 1 ;
			//KeyTable[EMU_RESET] = 0 ;
		}


		if ( g_Gamepads[0].wButtons & XINPUT_GAMEPAD_BACK )  
			IOPortB &= 0xFD ;
		else
			IOPortB |= 2 ;

	}

	if ( g_Gamepads[1].hDevice )
	{
		if ( g_Gamepads[1].bAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
			KeyTable[P2FIRE] = 0x80 ;
		else
			KeyTable[P2FIRE] = 0 ;

		if ( g_Gamepads[1].bAnalogButtons[ XINPUT_GAMEPAD_X ] ) 
			KeyTable[P2BG_B] = 0x80 ;
		else
			KeyTable[P2BG_B] = 0 ;

		if ( g_Gamepads[1].bAnalogButtons[ XINPUT_GAMEPAD_B ] ) 
			KeyTable[P2BG_T] = 0x80 ;
		else
			KeyTable[P2BG_T] = 0 ;

		if ( g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
			KeyTable[P2LEFT] = 0x80 ;
		else
			KeyTable[P2LEFT] = 0 ;

		if ( g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_UP ) 
			KeyTable[P2UP] = 0x80 ;
		else
			KeyTable[P2UP] = 0 ;

		if ( g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
			KeyTable[P2RIGHT] = 0x80 ;
		else
			KeyTable[P2RIGHT] = 0 ;

		if ( g_Gamepads[1].wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
			KeyTable[P2DOWN] = 0x80 ;
		else
			KeyTable[P2DOWN] = 0 ;

		/*
		if ( g_Gamepads[1].wButtons & XINPUT_GAMEPAD_START )  //reset
		{
			IOPortB &= 0xFE ;
		}
		else
		{
			IOPortB |= 1 ;
		}


		if ( g_Gamepads[1].wButtons & XINPUT_GAMEPAD_BACK )  
			IOPortB &= 0xFD ;
		else
			IOPortB |= 2 ;
*/
	}

	return 0 ;
}

/*
int ReadJoypad( int port )
{

	int value ;
	char xmsg[100] ;


	value = 0 ;
#define	JOY_A		0x01
#define	JOY_B		0x02
#define	JOY_SELECT	0x04
#define	JOY_START	0x08
#define	JOY_UP		0x10
#define	JOY_RIGHT	0x20
#define	JOY_DOWN	0x40
#define	JOY_LEFT	0x80
#define JOY_AUTOI	0x100
#define JOY_AUTOII	0x200

	updateCheats() ;

	XBInput_GetInput();

	if ( g_Gamepads[port].hDevice )
	{

		if ( g_Gamepads[port].bAnalogButtons[ XINPUT_GAMEPAD_A ] ) 
			value |= JOY_A ;
		if ( g_Gamepads[port].bAnalogButtons[ XINPUT_GAMEPAD_X ] ) 
			value |= JOY_B ;
		if ( g_Gamepads[port].wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) 
			value |= JOY_LEFT ;
		if ( g_Gamepads[port].wButtons & XINPUT_GAMEPAD_DPAD_UP ) 
			value |= JOY_UP ;
		if ( g_Gamepads[port].wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ) 
			value |= JOY_RIGHT ;
		if ( g_Gamepads[port].wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) 
			value |= JOY_DOWN ;
		if ( g_Gamepads[port].wButtons & XINPUT_GAMEPAD_START )  
			value |= JOY_START ;
		if ( g_Gamepads[port].wButtons & XINPUT_GAMEPAD_BACK )  
			value |= JOY_SELECT ;

		if ( g_Gamepads[port].bPressedAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER])
		{
			//bkgHalt = bkgHalt ^ 1 ;
		}

		if ( ( g_Gamepads[port].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) && 
			 (g_Gamepads[port].bPressedAnalogButtons[XINPUT_GAMEPAD_WHITE]) )
		{
			loadgame() ;
		}
		else if ( ( g_Gamepads[port].bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]) && 
			 (g_Gamepads[port].bPressedAnalogButtons[XINPUT_GAMEPAD_BLACK]) )
		{
			savegame() ;
		}

		//sprintf( xmsg, "x=%d,y=%d,x=%d,y=%d\r\n", g_Gamepads[port].sThumbRX, g_Gamepads[port].sThumbRX, g_Gamepads[port].fX2, g_Gamepads[port].fY2 ) ;

		if ( g_Gamepads[port].fX2 )
		{
			m_sound.adjust_volume( (int) ( g_Gamepads[port].fX2 * 25.0 ) ) ;
		}
		if ( g_Gamepads[port].fY2 )
		{
			m_mp3player.adjust_volume( (int) ( g_Gamepads[port].fY2 * 25.0 ) ) ;
		}
	
	}

	return value ;
}

*/




void CXBoxSample::initConsole( UINT32 idx )
{
	char                filename[500] ;
	char systemcard[200] ;

	global_error_message[0] = 0 ;

	m_numFrames = 0 ;
	m_droppedFrames = 0 ;
//	soundChannels = 0xFF ;
//	bkgHalt = 0 ;

	m_bAdjustMode = 0 ;
	m_msgtime = 0 ;

	xbox_last_x = xbox_last_y = xbox_curr_x = xbox_curr_y  = 0 ;


	memset( m_memMatches, 1, CONSOLE_MEMORY_SIZE ) ;
	m_currentMemMatches = CONSOLE_MEMORY_SIZE ;
	m_numCheats = 0 ;

	//writexbox( "init1" ) ;

	//strcpy((char*)filename, "D:\\z26roms\\" ) ;
	strcpy((char*)filename, m_szCurrentDir ) ;
	//wcsrtombs( (char*)gfilename, (const wchar_t**)(&(files[idx].name)), 100, NULL ) ;
	strcat( (char*)filename, (const char*)files[idx].filename ) ;



	if (strstr (strupr(filename), ".MP3"))
	{
		if ( m_mp3player.loadFile( filename, 1, 0, 70*60*75 ) )
		{
			//writexbox( "nonomp3\r\n") ;
		}
		else
		{
			m_mp3player.insertSilence( 22050 ) ;
			m_mp3player.pause( FALSE ) ;
			m_state = MAIN_MENU ;
			return  ;
		}
	}

	m_p1Difficulty = m_p2Difficulty = m_p1Down = m_p2Down = 0 ;

	char *p;


	//writexbox( "init1" ) ;

	strcpy( g_saveprefix, g_savePath ) ;
	strcat( g_saveprefix, "\\" ) ;
	strcat( g_saveprefix, strrchr( filename, '\\' )+1 ) ;
	//sprintf(saveprefix, "%s\\%s", savedir, (const char*)files[idx].filename);
	p = strchr(g_saveprefix, '.');
	if (p) *p = 0;


	
	strcpy( g_scrfile, "d:\\" ) ;
	strcat( g_scrfile, strrchr( filename, '\\' )+1 ) ;
	//sprintf(saveprefix, "%s\\%s", savedir, (const char*)files[idx].filename);
	p = strchr(g_scrfile, '.');
	if (p) *p = 0;
	strcat(g_scrfile, ".scr" ) ;

	
	strcpy(g_sramfile, g_saveprefix);
	strcat(g_sramfile, ".sav");


	strcpy(g_chtfile, g_saveprefix);
	strcat(g_chtfile, ".cht");

	sprintf( g_statefile, "%s.sta", g_saveprefix ) ;

//	nonoise = 0 ;
	
	//writexbox( "init1" ) ;

	m_sound.init() ;
	//m_mp3player.init() ;

	//writexbox( "init1" ) ;
	cht_load() ;
	//writexbox( "init1" ) ;

	// Create our texture
	init_texture();

	//writexbox( "init1" ) ;

	// Create our sprite driver
	if ( Sprite == NULL )
		D3DXCreateSprite(m_pd3dDevice, &Sprite);
	
	//writexbox( "init1" ) ;





	m_fAppTime = 0.0f ;

	g_dwStartTime = GetTickCount() ;
	g_dwTimePaused = 0 ;
	m_dwStartPause = 0 ;

	m_steps = 0 ;

	//writexbox( "init4" ) ;
	//Then start it up

	//m_sound.insertSilence( 61500 ) ;
	m_sound.pause( TRUE ) ;
	//m_mp3player.insertSilence( 22050 ) ;
	//m_mp3player.pause( FALSE ) ;

	//writexbox( "init5" ) ;
	z26main( filename ) ;

	//writexbox( "initout" ) ;
	m_state=MAIN_MENU ;

	//put 3 frames of data in the audio buffer
	//processEmu(FALSE) ;
	//processEmu(FALSE) ;
	//processEmu(FALSE) ;


}

void CXBoxSample::cleanupConsole( )
{
	//sram_save();
	//rtc_save();
	cht_save() ;


	if (m_cheatCodes != NULL)
	{
		free(m_cheatCodes);
		m_cheatCodes = NULL;
	}


}



#ifdef __cplusplus
extern "C" {
#endif


unsigned char* xbox_get_screen_buffer() 
{
	return g_app->g_pBlitBuff ;
}

int xbox_get_pitch() 
{
	return g_app->m_nPitch ;
}

int xbox_read_input(int port) 
{
	//writexbox( "before readinput") ;
	//return g_app->ReadJoypad( port ) ;
	//writexbox( "after readinput") ;
	return 0 ;
}

int xbox_check_events()
{
	//writexbox( "before events") ;
	return g_app->handleEvents() ;
	//writexbox( "after events") ;
	return 0 ;
}

void xbox_put_image( int x, int y, int w, int h)
{
	//writexbox( "before render") ;
	//g_sound->process() ;
	//g_mp3player->process() ;
	g_app->render_to_texture(x,y,w,h) ;
	g_app->m_sound.process() ;

	//writexbox( "after render") ;
}

void xbox_set_palette( unsigned int *palette )
{
	g_app->setPalette( palette) ;
}

void xbox_open_zip( char *hugozipfile )
{
	//writexbox( "before zip") ;
	//g_app->rom_load_zip( hugozipfile ) ;
	//writexbox( "after zip") ;
}

#ifdef __cplusplus
}
#endif

void CXBoxSample::processEmu( BOOL render )
{
			
			handleEvents();
			updateCheats() ;


//			doneFrame = 0 ;

			//m_nbytes = update_sound_main() ;



			if ( render )
			{
				//render_to_texture();
				m_numFrames++ ;
			}


//			m_droppedFrames += m_sound.process( (byte**)sbuf, m_nbytes, soundChannels ) ;

			while ( m_sound.m_bDanger )
			{
				handleEvents();
				updateCheats() ;
//				doneFrame = 0 ;
				//m_nbytes = update_sound_main() ;


				//m_droppedFrames += m_sound.process( (byte**)sbuf, m_nbytes, soundChannels ) ;
			}



}


int CXBoxSample::rom_load_zip( char *hugozipfile )
{
	byte *data ;
	int len = 0;

	//writexbox( "ttt\r\n" ) ;
    unzFile file = unzOpen(hugozipfile);

    if(file == NULL)
		return 0 ;

	//writexbox( "ttt\r\n" ) ;

    char filename[132];
    int filesize = 0;
    int port = unzGoToFirstFile(file);
    unz_file_info info;

	//writexbox( "ttt\r\n" ) ;
    while(port == UNZ_OK)
    {
		char name[132];
		unzGetCurrentFileInfo(file, &info, name,128, NULL,0, NULL,0);

		if ((int) info.uncompressed_size > filesize)
		{
			strcpy(filename,name);
			filesize = info.uncompressed_size;
		}
		port = unzGoToNextFile(file);
    }

	//writexbox( "ttt\r\n" ) ;
    if( !(port == UNZ_END_OF_LIST_OF_FILE || port == UNZ_OK) || filesize == 0)
    {
		unzClose(file) ;
		return 0 ;
    }
	//writexbox( "ttt\r\n" ) ;

    unzLocateFile(file,filename,1);
    unzGetCurrentFileInfo(file, &info, filename,128, NULL,0, NULL,0);
    
	//writexbox( "ttt\r\n" ) ;
    if( unzOpenCurrentFile(file) != UNZ_OK )
    {
		unzClose(file);
		return 0 ;
    }

	//writexbox( "ttt\r\n" ) ;

	data = (byte*)malloc( info.uncompressed_size ) ;

	//writexbox( "ttt\r\n" ) ;

	int l = unzReadCurrentFile(file,data,info.uncompressed_size);
	if(unzCloseCurrentFile(file) == UNZ_CRCERROR)
	{
		free(data) ;
	    unzClose(file);
		return 0 ;
	}

	//writexbox( "ttt\r\n" ) ;
    unzClose(file);

/*
	fsize = ftell (fp);

	fseek (fp, fsize & 0x1fff, SEEK_SET);
	fsize &= ~0x1fff;

	ROM = (UChar *) malloc (fsize);
	ROM_size = fsize / 0x2000;
	fread (ROM, 1, fsize, fp);
*/

	filesize = info.uncompressed_size ;
	filesize &= ~0x1fff;  //524288  524800

	//writexbox( "ttt\r\n" ) ;

	//ROM = (UChar *) malloc (filesize);
	//ROM_size = filesize / 0x2000;
	//memcpy(ROM, data + (info.uncompressed_size & 0x1fff), filesize ) ;

	free(data) ;

	//writexbox( "ttt\r\n" ) ;

	return 1;
}

