#include "mercury_sdk.h"

#define JR_RA 0x03E00008
#define SCREEN_HEIGHT 272
#define SCREEN_WIDTH  512
#define CMAX_X 60
#define CMAX_Y 38
#define LINESIZE 	512				//in long
#define FRAMESIZE  0xAA000			//in byte

#define TEXTCOLOUR 0x00FFFFFFL
#define BLACK      0x00000000L
#define BLUE       0x00FF0000L
#define RED        0x000000FFL
#define GREEN      0x0000FF00L

#define INDEX_BLACK      10
#define INDEX_WHITE      1
#define INDEX_PINK       2
#define INDEX_RED        3
#define INDEX_BLUE       4
#define INDEX_GREEN      5
#define INDEX_YELLOW     6
#define INDEX_CYAN       7
#define INDEX_GRAY       9
#define INDEX_DARKGREEN  0

#define 	FIO_S_ISLNK(m)   (((m) & FIO_S_IFMT) == FIO_S_IFLNK)
#define 	FIO_S_ISREG(m)   (((m) & FIO_S_IFMT) == FIO_S_IFREG)
#define 	FIO_S_ISDIR(m)   (((m) & FIO_S_IFMT) == FIO_S_IFDIR)
#define 	FIO_SO_ISLNK(m)   (((m) & FIO_SO_IFMT) == FIO_SO_IFLNK)
#define 	FIO_SO_ISREG(m)   (((m) & FIO_SO_IFMT) == FIO_SO_IFREG)
#define 	FIO_SO_ISDIR(m)   (((m) & FIO_SO_IFMT) == FIO_SO_IFDIR)
#define UMEM_TOP 0x08800000
#define UMEM_SIZE 0x01800000

#define TRUE  1
#define FALSE 0
#define NULL  (void *)0

enum  	IOAccessModes {
  FIO_S_IFMT = 0xF000, FIO_S_IFLNK = 0x4000, FIO_S_IFDIR = 0x1000, FIO_S_IFREG = 0x2000,
  FIO_S_ISUID = 0x0800, FIO_S_ISGID = 0x0400, FIO_S_ISVTX = 0x0200, FIO_S_IRWXU = 0x01C0,
  FIO_S_IRUSR = 0x0100, FIO_S_IWUSR = 0x0080, FIO_S_IXUSR = 0x0040, FIO_S_IRWXG = 0x0038,
  FIO_S_IRGRP = 0x0020, FIO_S_IWGRP = 0x0010, FIO_S_IXGRP = 0x0008, FIO_S_IRWXO = 0x0007,
  FIO_S_IROTH = 0x0004, FIO_S_IWOTH = 0x0002, FIO_S_IXOTH = 0x0001
};

SceUID (* sceIoMkdir)(const char *dir, SceMode mode) = NULL;
SceUID (* sceIoDopen)(const char *dir) = NULL;
SceUID (* sceIoDread)(SceUID fd, SceIoDirent *dir) = NULL;
SceUID (* sceIoDclose)(SceUID fd) = NULL;
SceUID (* sceIoAssign)(const char *dev1, const char *dev2, const char *dev3, int mode, void *unk1, long unk2) = NULL;
SceUID (* sceIoChstat) (const char *file, SceIoStat *stat, int bits) = NULL;

SceUID log;
int CodeBuf[12];
SceUID init_tests();
void log_dir(const char *dir);
void strcpy(char *out, char *in);
void strcat(char *out, char *in);

unsigned long colours[11];

typedef unsigned int  UINT;
typedef void          VOID;
typedef unsigned char BOOL;

int logdir_failed=0;

// get vram address for character position
unsigned char *GetVramAddr(unsigned long x,unsigned long y);

// print a single character
void PutChar(unsigned long x,unsigned long y,unsigned long color,unsigned long bgcolor,unsigned char ch,char drawfg,char drawbg,char mag);

// print a string
void Print(unsigned long x,unsigned long y,unsigned long color,const char *str);

// clear video ram
void Fillvram(unsigned long color);

void IoWriteNibble(SceUID fd, unsigned char val);

void WriteNibble(int x, int y, unsigned char val);

void WriteByte(int x, int y, unsigned char val);

void WriteDword(int x, int y, unsigned long val);

void DebugValue(int x, int y, char * label, unsigned long val);

void changeBuffer();

void IoWriteDecimal(SceUID fd, unsigned long val);

void WriteDecimal(int x, int y, unsigned long val);

void initScreenAndCtrl();

// font data
const unsigned char font[]={

    // much better charset, by eddie!
    // this is actually the 8x8 neuromancer
    // vga/ega mode font :)
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	 // 0x20
		0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,	 // 0x21
		0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,	 // 0x22
		0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00,	 // 0x23
		0x30,0x7C,0xC0,0x78,0x0C,0xF8,0x30,0x00,	 // 0x24
		0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00,	 // 0x25
		0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00,	 // 0x26
		0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,	 // 0x27
		0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,	 // 0x28
		0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,	 // 0x29
		0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,	 // 0x2A
		0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00,	 // 0x2B
		0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,	 // 0x2C
		0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,	 // 0x2D
		0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,	 // 0x2E
		0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,	 // 0x2F
		0x7C,0xC6,0xCE,0xDE,0xF6,0xE6,0x7C,0x00,	 // 0x30
		0x30,0x70,0x30,0x30,0x30,0x30,0xFC,0x00,	 // 0x31
		0x78,0xCC,0x0C,0x38,0x60,0xCC,0xFC,0x00,	 // 0x32
		0x78,0xCC,0x0C,0x38,0x0C,0xCC,0x78,0x00,	 // 0x33
		0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x1E,0x00,	 // 0x34
		0xFC,0xC0,0xF8,0x0C,0x0C,0xCC,0x78,0x00,	 // 0x35
		0x38,0x60,0xC0,0xF8,0xCC,0xCC,0x78,0x00,	 // 0x36
		0xFC,0xCC,0x0C,0x18,0x30,0x30,0x30,0x00,	 // 0x37
		0x78,0xCC,0xCC,0x78,0xCC,0xCC,0x78,0x00,	 // 0x38
		0x78,0xCC,0xCC,0x7C,0x0C,0x18,0x70,0x00,	 // 0x39
		0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,	 // 0x3A
		0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x60,	 // 0x3B
		0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x00,	 // 0x3C
		0x00,0x00,0xFC,0x00,0x00,0xFC,0x00,0x00,	 // 0x3D
		0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,	 // 0x3E
		0x78,0xCC,0x0C,0x18,0x30,0x00,0x30,0x00,	 // 0x3F
		0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00,	 // 0x40
		0x30,0x78,0xCC,0xCC,0xFC,0xCC,0xCC,0x00,	 // 0x41
		0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00,	 // 0x42
		0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,	 // 0x43
		0xF8,0x6C,0x66,0x66,0x66,0x6C,0xF8,0x00,	 // 0x44
		0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00,	 // 0x45
		0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00,	 // 0x46
		0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00,	 // 0x47
		0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,	 // 0x48
		0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,	 // 0x49
		0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00,	 // 0x4A
		0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00,	 // 0x4B
		0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,	 // 0x4C
		0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,	 // 0x4D
		0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00,	 // 0x4E
		0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00,	 // 0x4F
		0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,	 // 0x50
		0x78,0xCC,0xCC,0xCC,0xDC,0x78,0x1C,0x00,	 // 0x51
		0xFC,0x66,0x66,0x7C,0x6C,0x66,0xE6,0x00,	 // 0x52
		0x78,0xCC,0xE0,0x70,0x1C,0xCC,0x78,0x00,	 // 0x53
		0xFC,0xB4,0x30,0x30,0x30,0x30,0x78,0x00,	 // 0x54
		0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFC,0x00,	 // 0x55
		0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,	 // 0x56
		0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00,	 // 0x57
		0xC6,0xC6,0x6C,0x38,0x38,0x6C,0xC6,0x00,	 // 0x58
		0xCC,0xCC,0xCC,0x78,0x30,0x30,0x78,0x00,	 // 0x59
		0xFE,0xC6,0x8C,0x18,0x32,0x66,0xFE,0x00,	 // 0x5A
		0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,	 // 0x5B
		0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,	 // 0x5C
		0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,	 // 0x5D
		0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,	 // 0x5E
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,	 // 0x5F
		0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,	 // 0x60
		0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00,	 // 0x61
		0xE0,0x60,0x60,0x7C,0x66,0x66,0xDC,0x00,	 // 0x62
		0x00,0x00,0x78,0xCC,0xC0,0xCC,0x78,0x00,	 // 0x63
		0x1C,0x0C,0x0C,0x7C,0xCC,0xCC,0x76,0x00,	 // 0x64
		0x00,0x00,0x78,0xCC,0xFC,0xC0,0x78,0x00,	 // 0x65
		0x38,0x6C,0x60,0xF0,0x60,0x60,0xF0,0x00,	 // 0x66
		0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8,	 // 0x67
		0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00,	 // 0x68
		0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,	 // 0x69
		0x0C,0x00,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,	 // 0x6A
		0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00,	 // 0x6B
		0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,	 // 0x6C
		0x00,0x00,0xCC,0xFE,0xFE,0xD6,0xC6,0x00,	 // 0x6D
		0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0x00,	 // 0x6E
		0x00,0x00,0x78,0xCC,0xCC,0xCC,0x78,0x00,	 // 0x6F
		0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0,	 // 0x70
		0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E,	 // 0x71
		0x00,0x00,0xDC,0x76,0x66,0x60,0xF0,0x00,	 // 0x72
		0x00,0x00,0x7C,0xC0,0x78,0x0C,0xF8,0x00,	 // 0x73
		0x10,0x30,0x7C,0x30,0x30,0x34,0x18,0x00,	 // 0x74
		0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00,	 // 0x75
		0x00,0x00,0xCC,0xCC,0xCC,0x78,0x30,0x00,	 // 0x76
		0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x6C,0x00,	 // 0x77
		0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00,	 // 0x78
		0x00,0x00,0xCC,0xCC,0xCC,0x7C,0x0C,0xF8,	 // 0x79
		0x00,0x00,0xFC,0x98,0x30,0x64,0xFC,0x00,	 // 0x7A
		0x1C,0x30,0x30,0xE0,0x30,0x30,0x1C,0x00,	 // 0x7B
		0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,	 // 0x7C
		0xE0,0x30,0x30,0x1C,0x30,0x30,0xE0,0x00,	 // 0x7D
		0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,	 // 0x7E
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

};

unsigned char *vramtop=(unsigned char *)0x04000000;
unsigned long drawframe;

// get vram address for character position
unsigned char *GetVramAddr(unsigned long x,unsigned long y)
{
	return vramtop+(drawframe?FRAMESIZE:0)+x*4+y*LINESIZE*4+0x40000000;
}

// print a single character
void PutChar(unsigned long x,unsigned long y,unsigned long color,unsigned long bgcolor,unsigned char ch,char drawfg,char drawbg,char mag)
{
	unsigned char *vptr0;		//pointer to vram
	unsigned char *vptr;		//pointer to vram
	const unsigned char *cfont;		//pointer to font
	unsigned long cx,cy;
	unsigned long b;
	char mx,my;

	cfont=font+ch*8;

	vptr0=GetVramAddr(x,y);

	for (cy=0; cy<8; cy++)
	{
		for (my=0; my<mag; my++)
		{
			vptr=vptr0;
			b=0x80;
			for (cx=0; cx<8; cx++)
			{
				for (mx=0; mx<mag; mx++)
				{
					if ((*cfont&b)!=0)
					{
						if (drawfg)
            {
              *(unsigned long *)vptr=color;
            }
					}
          else
          {
						if (drawbg)
            {
              *(unsigned long *)vptr=bgcolor;
            }
					}
					vptr+=4;
				}
				b=b>>1;
			}
			vptr0+=LINESIZE*4; // 2
		}
		cfont++;
	}
}

// print a string
void Print(unsigned long x,unsigned long y,unsigned long color,const char *str)
{
	while (*str!=0 && x<CMAX_X && y<CMAX_Y) {
		PutChar(x*8,y*8,color,0,*str,1,1,1);
		str++;
		x++;
		if (x>=CMAX_X) {
			x=0;
			y++;
		}
	}
}

// clear video ram
void Fillvram(unsigned long color)
{
	unsigned char *vptr0;		//pointer to vram
	unsigned long i;

	vptr0=GetVramAddr(0,0);

	for (i=0; i<(FRAMESIZE/4); i++)
	{
		*(unsigned long *)vptr0=color;
		vptr0+=4;
	}
}

void changeBuffer()
{
	sceDisplayWaitVblankStart();

	sceDisplaySetFrameBuf(
			(void*)GetVramAddr(0,0),
			512,
			PSP_DISPLAY_PIXEL_FORMAT_8888
			,0);

	drawframe=(drawframe?0:1);
}

void initScreenAndCtrl()
{
	drawframe = 0;
	sceDisplaySetMode(0,SCREEN_WIDTH,SCREEN_HEIGHT);

	sceDisplaySetFrameBuf(
			(void*)vramtop,
			512,
			PSP_DISPLAY_PIXEL_FORMAT_8888
			,1);
	Fillvram(0x00000000);
	drawframe = 1;
	Fillvram(0x00000000);
	sceCtrlSetSamplingMode(1);
}

SceCtrlData gpaddata;

void InitGlobals()
{
	colours[10] = 0x00000000L;
 	colours[1] = 0x00FFFFFFL;
 	colours[2] = 0x00FF00FFL;
 	colours[3] = 0x000000FFL;
 	colours[4] = 0x00FF0000L;
 	colours[5] = 0x0000FF00L;
 	colours[6] = 0x0000FFFFL;
 	colours[7] = 0x00FFFF00L;
 	colours[8] = 0x00FFFF88L;
 	colours[9] = 0x00888888L;
 	colours[0] = 0x00008800L;
}

int drives=0;

void main(unsigned long arglen, unsigned long *argp)
{
	sceKernelDcacheWritebackAll();
	InitGlobals();

	initScreenAndCtrl();

	log = sceIoOpen("ef0:/log.txt", PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);
	if((getSyscallForFunc(sceIoOpen) == getSyscallForFunc(sceIoCloseAsync) - 33) || (getSyscallForFunc(sceIoOpen) == getSyscallForFunc(sceIoCloseAsync) + 4))
	{
		CodeBuf[0] = JR_RA; // jr $ra
		CodeBuf[2] = JR_RA; // jr $ra
		CodeBuf[4] = JR_RA; // jr $ra
		CodeBuf[6] = JR_RA; // jr $ra
		CodeBuf[8] = JR_RA; // jr $ra
		CodeBuf[10] = JR_RA; // jr $ra
		if((getSyscallForFunc(sceIoOpen) == getSyscallForFunc(sceIoCloseAsync) - 33))
		{
			CodeBuf[1] = getOpcodeForSyscall(getSyscallForFunc(sceIoCloseAsync)-6);
		} else {
			CodeBuf[1] = 0xC;//getOpcodeForSyscall(getSyscallForFunc(sceIoOpen)-3);
		}
		CodeBuf[3] = getOpcodeForSyscall(getSyscallForFunc(sceIoReadAsync)+5);
		CodeBuf[5] = getOpcodeForSyscall(getSyscallForFunc(sceIoReadAsync)+10);
		CodeBuf[7] = getOpcodeForSyscall(getSyscallForFunc(sceIoReadAsync)+13);
		CodeBuf[9] = getOpcodeForSyscall(getSyscallForFunc(sceIoReadAsync)+6);
		CodeBuf[11] = getOpcodeForSyscall(getSyscallForFunc(sceIoGetstat)+4);
		
		sceIoMkdir = CodeBuf;
		sceIoDopen = CodeBuf+2;
		sceIoDread = CodeBuf+4;
		sceIoDclose = CodeBuf+6;
		sceIoAssign = CodeBuf+8;
		sceIoChstat = CodeBuf+10;
		io_write_string(log, "\nsceIoOpen=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoOpen));
		io_write_string(log, "\nsceIoCloseAsync=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoCloseAsync));
		io_write_string(log, "\nsceIoMkdir=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoMkdir));
		io_write_string(log, "\nsceIoDopen=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoDopen));
		io_write_string(log, "\nsceIoDread=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoDread));
		io_write_string(log, "\nsceIoDclose=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoDclose));
		io_write_string(log, "\nsceIoAssign=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoAssign));
		io_write_string(log, "\nsceIoGetstat=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoGetstat));
		io_write_string(log, "\nsceIoChstat=syscall ");
		io_write_hex(log, getSyscallForFunc(sceIoChstat));
		sceIoClose(log);

		log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_CREAT|PSP_O_TRUNC, 0777);
		io_write_string(log, "<title>Drive Bruteforce Results</title>\n<table><tr><td colspan=\"2\">Drive Bruteforce Results</td></tr>\n");
		sceIoClose(log);
		SceUID res = init_tests();
		if(res < 0)
		{
			Print(0,0,colours[INDEX_WHITE],"Failed to find syscalls... [logdir_failed]");
			Print(0,1,colours[INDEX_WHITE],"Press any button to exit.");
			changeBuffer();
			sceCtrlReadBufferPositive(&gpaddata,1);
			log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
			io_write_string(log, "</table><div style=\"color:red;\">syscall resolution fails - ");
			io_write_string(res, res & 0x01000000 ? "sceIoDopen" : res & 0x02000000 ? "sceIoDread" : "sceIoDclose");
			io_write_string(log, "</div>");
			sceIoClose(log);
			sceKernelDelayThread(1500000);
			sceKernelExitGame();
			return;
		}

		Fillvram(colours[INDEX_BLACK]);    
		Print(0,0,colours[INDEX_WHITE], "syscalls hooked OK. proceeding...");
		changeBuffer();
		char tmpbuf[16];
		memset(tmpbuf, 0, 16);
		recursive_bruteforce(tmpbuf);

		Fillvram(colours[INDEX_BLACK]);    
		if(logdir_failed == 1)
		{
			Print(0,0,colours[INDEX_WHITE],"Failed to find syscalls... [logdir_failed]");
		} else {
			Print(0, 0, colours[INDEX_GREEN],"Done!");
			Print(0, 1, colours[INDEX_GREEN], "Drives found: ");
			WriteDecimal(14, 1, drives+1);
			log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
			io_write_string(log,"</table>\n<div style=\"color: green;\">Drives found: ");
			IoWriteDecimal(log, drives+1);
			io_write_string(log,"</div>");
			sceIoClose(log);
		}
	} else {
		Fillvram(colours[INDEX_BLACK]);    
		Print(0,0,colours[INDEX_WHITE],"Failed to find syscalls... in main after testing");
		log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
		io_write_string(log, "</table><div style=\"color:red;\">syscall resolution fails</div>");
		sceIoClose(log);
	}
	Print(0,2,colours[INDEX_WHITE],"Press any button to exit.");
	changeBuffer();
	sceCtrlReadBufferPositive(&gpaddata,1);
	sceKernelDelayThread(1500000);

	sceKernelExitGame();
	return;
}

void strcpy(char *out, char *in)
{
	int i;
	if(in[0]=='\0'){out[0]='\0';return;}
	for(i=0;i<strlen(in);i++)
		out[i]=in[i];
	out[strlen(in)]='\0';
}

void strcat(char *out, char *in)
{	
	int i, j;
	for(i=strlen(out),j=0;j<strlen(in);j++)
		out[i+j]=in[j];
	out[i+strlen(in)]='\0';
}

void WriteNibble(int x, int y, unsigned char val)
{
	char hexchars[17] = "0123456789ACBDEF";
	PutChar(x*8,y*8,TEXTCOLOUR,0,hexchars[val],1,1,1);
}

void WriteByte(int x, int y, unsigned char val)
{
	char lchr;

	lchr = (val & 0xF0) >> 4;
	WriteNibble(x,y,lchr);
	lchr = (val & 0xF);
	WriteNibble(x+1,y,lchr);
}

void WriteDword(int x, int y, unsigned long val)
{
	WriteByte(x,y,(val & 0xFF000000L) >> 24);
	WriteByte(x+2,y,(val & 0xFF0000L) >> 16);
	WriteByte(x+4,y,(val & 0xFF00L) >> 8);
	WriteByte(x+6,y,(val & 0xFFL));
}

void IoWriteNibble(SceUID fd, unsigned char val)
{
	char *hexchars = "0123456789ACBDEF";
	sceIoWrite(fd, hexchars+val, 1);
}

void DebugValue(int x, int y, char * label, unsigned long val)
{
	Print(x,y,TEXTCOLOUR,label);
	WriteDword(strlen(label),y,val);
}

void WriteDecimal(int x, int y, unsigned long val)
{
	unsigned long divisor = 1000000000L;
	unsigned char nibble;

	val = val % 1000000000L;

	while (divisor > 0)
	{
		nibble = val / divisor;

		WriteNibble(x, y, nibble);

		val = val - (nibble * divisor);
		x++;
		divisor /= 10;
	}
}

void IoWriteDecimal(SceUID fd, unsigned long val)
{
	unsigned long divisor = 10000000L;
	unsigned char nibble;

	val = val % 100000000L;

	while (divisor > 0)
	{
		nibble = val / divisor;

		IoWriteNibble(fd, nibble);

		val = val - (nibble * divisor);
		divisor /= 10;
	}
}

void recursive_bruteforce(char *s)
{
	char tmpbuf[16];
	memset(tmpbuf, 0, 16);
	int i, j;
	for(i=0;i<26;i++)
	{
		if(strlen(s)<5)
		{
			int k = strlen(s);
			s[k]=i+0x61;
			strcpy(tmpbuf, s);
			strcat(tmpbuf, ":");
			test_drive(tmpbuf);
			strcat(tmpbuf, "/");
			test_drive(tmpbuf);
			for(j=0;j<10;j++)
			{
				memset(tmpbuf, 0, 16);
				strcpy(tmpbuf, s);
				tmpbuf[strlen(tmpbuf)]="0123456789"[j];
				strcat(tmpbuf, ":/");
				test_drive(tmpbuf);
			}
			recursive_bruteforce(s);
			s[strlen(s)-1]='\0';
		}
	}
}

void test_drive(char *s)
{
	Fillvram(colours[INDEX_BLACK]);    
	Print(0,0,colours[INDEX_WHITE], "syscalls hooked OK. proceeding...");
	Print(0,1,colours[INDEX_WHITE], "Testing drive: ");
	Print(15,1,colours[INDEX_WHITE],s);
	DebugValue(0,6,"Drives found so far: ",drives+1);
	changeBuffer();
	SceUID res=sceIoDopen(s);
	sceIoDclose(res);
	if(res != 0x80020321 && res != 0x80020149)
	{
		if(res == 0x800200D3)
		{
			Fillvram(colours[INDEX_BLACK]);    
			Print(0,0,colours[INDEX_WHITE],"Failed to find syscalls... [0x800200D3]");
			changeBuffer();
			log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
			io_write_string(log, "<tr><td colspan=\"2\" style=\"color:red;\">sceIoDclose fails, res=0x800200D3</td></tr>\n");
			sceIoClose(log);
		} else {
			drives++;
			Fillvram(colours[INDEX_BLACK]);    
			Print(0,0,colours[INDEX_WHITE], "syscalls hooked OK. proceeding...");
			Print(0,1,colours[INDEX_WHITE],"Testing drive: ");
			Print(15,1,colours[INDEX_WHITE],s);
			Print(0,3,colours[INDEX_GREEN]," -- HIT! Dumping layout to dir.htm");
			DebugValue(0,6,"Drives found so far: ",drives+1);
			changeBuffer();
			log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
			io_write_string(log, "<tr><td colspan=\"2\" style=\"color:blue;\"><h1>Contents of ");
			io_write_string(log, s);
			io_write_string(log, "</h1></td></tr>\n");
			sceIoClose(log);
			log_dir(s);
		}
	}
}

SceUID init_tests()
{
	SceUID res, dl = sceIoDopen("ef0:/");
	if(dl<0) return dl+0x01000000;
	SceIoDirent sid;
	memset(&sid, 0, sizeof(SceIoDirent));
	res=sceIoDread(dl, &sid);
	if(res<0) return res+0x02000000;
	res=sceIoDclose(dl);
	if(res<0) return res+0x04000000;
	return 0;
}

void log_dir(const char *dir) // recursively list the contents of a directory, excluding the root itself
{
	if(logdir_failed == 1)return;
	SceUID res;
	SceUID dl = sceIoDopen(dir);

	log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
	io_write_string(log, "<tr><td colspan=\"2\" style=\"border-top: 1px black solid;\"><b>");
	io_write_string(log, dir);
	io_write_string(log,"</b></td></tr>\n");
	sceIoClose(log);

	if(dl < 0)
	{
		log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
		io_write_string(log, "<tr><td colspan=\"2\" style=\"color:red;\">sceIoDopen fails, res=");
		io_write_hex(log, dl);
		if(res == 0x80020321)
			io_write_string(log, " (device not found)");
		if(res == 0x80020325)
		{
			io_write_string(log, " (operation not supported)");
			SceUID dl2 = sceIoOpen(dir, PSP_O_RDONLY, 0777);
			if(dl2>=0)
				io_write_string(log, " (probably a block device)");
			sceIoClose(dl2);
		}
		io_write_string(log, "</td></tr>\n");
		sceIoClose(log);
		return;
	}

	SceIoDirent sid;
	memset(&sid, 0, sizeof(SceIoDirent));
	while(res=sceIoDread(dl, &sid))
	{
		if(res == 0x8002012E)
		{
			Fillvram(colours[INDEX_BLACK]);    
			Print(0,0,colours[INDEX_WHITE],"Failed to find syscalls... [0x8002012E]");
			changeBuffer();
			logdir_failed=1;
	
			log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
			io_write_string(log, "<tr><td colspan=\"2\" style=\"color:red;\">sceIoDread fails, res=");
			io_write_hex(log, res);
			io_write_string(log, "</td></tr>\n");
			sceIoClose(log);
	
			return;
		}
		if(res<0)
		{
	
			log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
			io_write_string(log, "<tr><td colspan=\"2\" style=\"color:red;\">sceIoDread fails, res=");
			io_write_hex(log, res);
			if(res == 0x80020321)
				io_write_string(log, " (device not found)");
			if(res == 0x80020325)
				io_write_string(log, " (operation not supported)");
			io_write_string(log, "</td></tr>\n");
			sceIoClose(log);
	
			return;
		}
		if(sid.d_name[0] == '.') continue;

		char compPath[0x200];
		strcpy(compPath, dir);
		if(compPath[strlen(compPath)-1] != '/')
			strcat(compPath, "/");
		strcat(compPath, sid.d_name);
		if(FIO_S_ISDIR(sid.d_stat.st_mode))
		{
			log_dir(compPath);
			continue;
		}

		log = sceIoOpen("ef0:/dir.htm", PSP_O_WRONLY|PSP_O_APPEND, 0777);
		io_write_string(log, "<tr><td>");
		io_write_string(log, sid.d_name);
		io_write_string(log, "</td><td>");
		if(!FIO_S_ISDIR(sid.d_stat.st_mode))
		{
			io_write_string(log, " <i>file - size: ");
			IoWriteDecimal(log, (unsigned int)sid.d_stat.st_size);
			io_write_string(log, " bytes</i>");
		} else {
			io_write_string(log, "&nbsp;");
		}
		io_write_string(log, "</td></tr>\n");
		sceIoClose(log);

	
		memset(&sid, 0, sizeof(SceIoDirent));
	}
	res = sceIoDclose(dl);
}
