// PSAR dumper for Updater data 
// Original author: PspPet
//
// Contributions:
//
// Vampire (bugfixes)
// Nem (ipl decryption)
// Dark_AleX (2.60-2.80 decryption)
// Noobz (3.00-3.02 decryption)
// Team C+D (3.03-3.52 decryption)
// M33 Team (3.60-3.71 decryption) + recode for 2.XX+ kernels 

#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspsuspend.h>
#include <psppower.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

#include <libpsardumper.h>
#include <pspdecrypt.h>

PSP_MODULE_INFO("PopsloaderExtracter", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(0);

#define printf    pspDebugScreenPrintf

////////////////////////////////////////////////////////////////////
// big buffers for data. Some system calls require 64 byte alignment

// big enough for the full PSAR file

#define PSAR_BUFFER_SIZE	9400000

static u8 g_dataPSAR[PSAR_BUFFER_SIZE] __attribute__((aligned(64))); 

// big enough for the largest (multiple uses)
static u8 g_dataOut[3000000] __attribute__((aligned(0x40)));
   
// for deflate output
//u8 g_dataOut2[3000000] __attribute__((aligned(0x40)));
static u8 *g_dataOut2;   

void ErrorExit(int milisecs, char *fmt, ...)
{
	va_list list;
	char msg[256];	

	va_start(list, fmt);
	vsprintf(msg, fmt, list);
	va_end(list);

	printf(msg);
	
	sceKernelDelayThread(milisecs*1000);
	sceKernelExitGame();
}

////////////////////////////////////////////////////////////////////
// File helpers

int ReadFile(char *file, int seek, void *buf, int size)
{
	SceUID fd = sceIoOpen(file, PSP_O_RDONLY, 0);
	if (fd < 0)
		return fd;

	if (seek > 0)
	{
		if (sceIoLseek(fd, seek, PSP_SEEK_SET) != seek)
		{
			sceIoClose(fd);
			return -1;
		}
	}

	int read = sceIoRead(fd, buf, size);
	
	sceIoClose(fd);
	return read;
}

int WriteFile(char *file, void *buf, int size)
{
	SceUID fd = sceIoOpen(file, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);
	
	if (fd < 0)
	{
		return fd;
	}

	int written = sceIoWrite(fd, buf, size);

	sceIoClose(fd);
	return written;
}

static char com_table[0x4000];
static int comtable_size;

static char _1g_table[0x4000];
static int _1gtable_size;

static char _2g_table[0x4000];
static int _2gtable_size;

static char _3g_table[0x4000];
static int _3gtable_size;

enum
{
	MODE_ENCRYPT_SIGCHECK,
	MODE_ENCRYPT,
	MODE_DECRYPT,
};

static int FindTablePath(char *table, int table_size, char *number, char *szOut)
{
	int i, j, k;

	for (i = 0; i < table_size-5; i++)
	{
		if (strncmp(number, table+i, 5) == 0)
		{
			for (j = 0, k = 0; ; j++, k++)
			{
				if (table[i+j+6] < 0x20)
				{
					szOut[k] = 0;
					break;
				}

				if (table[i+5] == '|' && !strncmp(table+i+6, "flash", 5) &&
					j == 6)
				{
					szOut[6] = ':';
					szOut[7] = '/';
					k++;
				}
				else if (table[i+5] == '|' && !strncmp(table+i+6, "ipl", 3) &&
					j == 3)
				{
					szOut[3] = ':';
					szOut[4] = '/';
					k++;
				}
				else
				{				
					szOut[k] = table[i+j+6];
				}
			}

			return 1;
		}
	}

	return 0;
}
/*
static int FindReboot(u8 *input, u8 *output, int size)
{
	int i;

	for (i = 0; i < (size - 0x30); i++)
	{
		if (memcmp(input+i, "~PSP", 4) == 0)
		{
			size = *(u32 *)&input[i+0x2C];

			memcpy(output, input+i, size);
			return size;
		}
	}

	return -1;
}

static void ExtractReboot(int mode, char *loadexec, char *reboot, char *rebootname)
{
	int s = ReadFile(loadexec, 0, g_dataOut, sizeof(g_dataOut));

	if (s <= 0)
		return;
	
	printf("Extracting %s... ", rebootname);

	if (mode != MODE_DECRYPT)
	{
		if (mode == MODE_ENCRYPT_SIGCHECK)
		{
			memcpy(g_dataOut2, g_dataOut, s);
			pspSignCheck(g_dataOut2);

			if (WriteFile(loadexec, g_dataOut2, s) != s)
			{
				ErrorExit(5000, "Cannot write %s.\n", loadexec);
			}
		}
			
		s = pspDecryptPRX(g_dataOut, g_dataOut2, s);
		if (s <= 0)
		{
			ErrorExit(5000, "Cannot decrypt %s.\n", loadexec);
		}

		s = pspDecompress(g_dataOut2, g_dataOut, sizeof(g_dataOut));
		if (s <= 0)
		{
			ErrorExit(5000, "Cannot decompress %s.\n", loadexec);
		}
	}

	s = FindReboot(g_dataOut, g_dataOut2, s);
	if (s <= 0)
	{
		ErrorExit(5000, "Cannot find %s inside loadexec.\n", rebootname);
	}

	s = pspDecryptPRX(g_dataOut2, g_dataOut, s);
	if (s <= 0)
	{
		ErrorExit(5000, "Cannot decrypt %s.\n", rebootname);
	}

	WriteFile(reboot, g_dataOut, s);

	s = pspDecompress(g_dataOut, g_dataOut2, sizeof(g_dataOut));
	if (s <= 0)
	{
		ErrorExit(5000, "Cannot decompress %s (0x%08X).\n", rebootname, s);
	}

	if (WriteFile(reboot, g_dataOut2, s) != s)
	{
		ErrorExit(5000, "Cannot write %s.\n", reboot);
	}

	printf("done.\n");
}*/

static char *GetVersion(char *buf)
{
	char *p = strrchr(buf, ',');

	if (!p)
		return NULL;

	return p+1;
}

static int is5Dnum(char *str)
{
	int len = strlen(str);

	if (len != 5)
		return 0;

	int i;

	for (i = 0; i < len; i++)
	{
		if (str[i] < '0' || str[i] > '9')
			return 0;
	}

	return 1;
}

int LoadStartModule(char *module, int partition)
{
	SceUID mod = kuKernelLoadModule(module, 0, NULL);

	if (mod < 0)
		return mod;

	return sceKernelStartModule(mod, 0, NULL, NULL, NULL);
}

int Expand(char *pbp, int argc, char **argv){
	int mode=MODE_DECRYPT, res;
	u8 pbp_header[0x28];
	SceUID fd;
	int error = 0;
	int psar_pos = 0, psar_offs;
	int table_mode;
	printf("Loading %s... ",pbp);

//initialize global vars
comtable_size=_1gtable_size=_2gtable_size=_3gtable_size=0;

	if (ReadFile(pbp, 0, pbp_header, sizeof(pbp_header)) != sizeof(pbp_header)){
		if(!strcmp(pbp,"ms0:/401.PBP")){
			SceUID fd = sceIoOpen("ms0:/seplugins/popsloader/impose.prx", PSP_O_RDONLY, 0);
			if(fd<0)ErrorExit(5000, "Cannot find ms0:/401.PBP, whose impose.prx is required for popsloader.\n");
			sceIoClose(fd);
		}
		printf("Cannot find %s.\n",pbp);return 1;
	}

	psar_offs = *(u32 *)&pbp_header[0x24];
	fd = sceIoOpen(pbp, PSP_O_RDONLY, 0);
	
	int cbFile = sceIoLseek32(fd, 0, PSP_SEEK_END) - psar_offs;
	sceIoLseek32(fd, psar_offs, PSP_SEEK_SET);

	if (sceIoRead(fd, g_dataPSAR, PSAR_BUFFER_SIZE) <= 0)
	{
		printf("Error Reading %s.\n",pbp);return 1;
	}
	
	//printf("PSAR file loaded (%d bytes)\n", cbFile);

    if (memcmp(g_dataPSAR, "PSAR", 4) != 0)
    {
        printf("Not a PSAR file\n");return 1;
    }
   
	res = pspPSARInit(g_dataPSAR, g_dataOut, g_dataOut2);
	if (res < 0)
	{
		ErrorExit(5000, "pspPSARInit failed with error 0x%08X!.\n", res);
	}

	char *version = GetVersion((char *)g_dataOut+0x10);
	printf("Version %s ", version);

	if (memcmp(version, "3.8", 3) == 0 || memcmp(version, "3.9", 3) == 0)
	{
		table_mode = 1;
	}
	else if (memcmp(version, "4.0", 3) == 0)
	{
		table_mode = 2;
	}
	else if (memcmp(version, "5.0", 3) == 0 || (memcmp(version, "5.5", 3) == 0))
	{
		table_mode = 3;
	}
	else if (memcmp(version, "6.0", 3) == 0 || (memcmp(version, "6.1", 3) == 0))
	{
		table_mode = 4;
	}
	else
	{
		table_mode = 0;
	}

	printf("(table_mode = %d)\n", table_mode);

/*
    sceIoMkdir("ms0:/F0", 0777);
	sceIoMkdir("ms0:/F0/PSARDUMPER", 0777);
	sceIoMkdir("ms0:/F0/codepage", 0777);
	sceIoMkdir("ms0:/F0/data", 0777);
	sceIoMkdir("ms0:/F0/dic", 0777);
	sceIoMkdir("ms0:/F0/font", 0777);
	sceIoMkdir("ms0:/F0/kd", 0777);
	sceIoMkdir("ms0:/F0/vsh", 0777);
	sceIoMkdir("ms0:/F0/data/cert", 0777);
	sceIoMkdir("ms0:/F0/kd/resource", 0777);
	sceIoMkdir("ms0:/F0/vsh/etc", 0777);
	sceIoMkdir("ms0:/F0/vsh/module", 0777);
	sceIoMkdir("ms0:/F0/vsh/resource", 0777);
*/

    while (1){
		char name[128];
		int cbExpanded;
		int pos;
		int signcheck;

		//get next file
		int res = pspPSARGetNextFile(g_dataPSAR, cbFile, g_dataOut, g_dataOut2, name, &cbExpanded, &pos, &signcheck);
		if(res < 0){
			if(error)ErrorExit(5000, "PSAR decode error, pos=0x%08X.\n", pos);
			int dpos = pos-psar_pos;
			psar_pos = pos;
			error = 1;
			memmove(g_dataPSAR, g_dataPSAR+dpos, PSAR_BUFFER_SIZE-dpos);

			if(sceIoRead(fd, g_dataPSAR+(PSAR_BUFFER_SIZE-dpos), dpos) <= 0)ErrorExit(5000, "Error Reading EBOOT.PBP.\n");
			pspPSARSetBufferPosition(psar_pos);
			continue;
		}
		else if (res == 0) /* no more files */
			break;

		//find table
		if (is5Dnum(name)){
			if (strcmp(name, "00001") != 0 && strcmp(name, "00002") != 0 && strcmp(name, "00003") != 0){
				int found = 0;
				
				if (_1gtable_size > 0)
					found = FindTablePath(_1g_table, _1gtable_size, name, name);

				if (!found && _2gtable_size > 0)
					found = FindTablePath(_2g_table, _2gtable_size, name, name);

				if (!found && _3gtable_size > 0)
					found = FindTablePath(_3g_table, _3gtable_size, name, name);

				if (!found){
					printf("Warning: cannot find path of %s\n", name);
					//sceKernelDelayThread(2*1000*1000);
					error = 0;
					continue;
				}
			}
		}else if (!strncmp(name, "com:", 4) && comtable_size > 0){
			if (!FindTablePath(com_table, comtable_size, name+4, name)){
				printf("Warning: cannot find path of %s\n", name);
				//sceKernelDelayThread(2*1000*1000);
				error = 0;
				continue;
				//ErrorExit(5000, "Error: cannot find path of %s.\n", name);
			}
		}else if (!strncmp(name, "01g:", 4) && _1gtable_size > 0){
			if (!FindTablePath(_1g_table, _1gtable_size, name+4, name))
				ErrorExit(5000, "Error: cannot find path of %s.\n", name);
		}else if (!strncmp(name, "02g:", 4) && _2gtable_size > 0){
			if (!FindTablePath(_2g_table, _2gtable_size, name+4, name))
				ErrorExit(5000, "Error: cannot find path of %s.\n", name);
		}

        //printf("'%s' ", name);

		char* szFileBase = strrchr(name, '/');


		if (szFileBase != NULL)
			szFileBase++;  // after slash
		else
			szFileBase = "err.err";

		//set destination
		if(cbExpanded > 0){
			char szDataPath[128];
			
			if (!strncmp(name, "flash0:/", 8))sprintf(szDataPath, "ms0:/F0/%s", name+8);
			else if (!strncmp(name, "flash1:/", 8))sprintf(szDataPath, "ms0:/F1/%s", name+8);
			else if (!strcmp(name, "com:00000")){
				comtable_size = pspDecryptTable(g_dataOut2, g_dataOut, cbExpanded, table_mode);
							
				if (comtable_size <= 0)
					ErrorExit(5000, "Cannot decrypt common table.\n");

				if (comtable_size > sizeof(com_table))
					ErrorExit(5000, "Com table buffer too small. Recompile with bigger buffer.\n");

				memcpy(com_table, g_dataOut2, comtable_size);						
				strcpy(szDataPath, "ms0:/F0/PSARDUMPER/common_files_table.bin");
			}else if (!strcmp(name, "01g:00000") || !strcmp(name, "00001")){
				_1gtable_size = pspDecryptTable(g_dataOut2, g_dataOut, cbExpanded, table_mode);
					
				if (_1gtable_size <= 0)
					ErrorExit(5000, "Cannot decrypt 1g table.\n");

				if (_1gtable_size > sizeof(_1g_table))
					ErrorExit(5000, "1g table buffer too small. Recompile with bigger buffer.\n");

				memcpy(_1g_table, g_dataOut2, _1gtable_size);						
				strcpy(szDataPath, "ms0:/F0/PSARDUMPER/1000_files_table.bin");
			}else if (!strcmp(name, "02g:00000") || !strcmp(name, "00002")){
				_2gtable_size = pspDecryptTable(g_dataOut2, g_dataOut, cbExpanded, table_mode);
							
				if (_2gtable_size <= 0)
					ErrorExit(5000, "Cannot decrypt 2g table %08X.\n", _2gtable_size);

				if (_2gtable_size > sizeof(_2g_table))
					ErrorExit(5000, "2g table buffer too small. Recompile with bigger buffer.\n");

				memcpy(_2g_table, g_dataOut2, _2gtable_size);						
				strcpy(szDataPath, "ms0:/F0/PSARDUMPER/2000_files_table.bin");
			}else if (!strcmp(name, "00003")){
				_3gtable_size = pspDecryptTable(g_dataOut2, g_dataOut, cbExpanded, table_mode);
							
				if (_3gtable_size <= 0){
					// We don't have yet the keys for table of 3000, they are only in mesg_led03g.prx
					printf("Cannot decrypt 3g table %08X.\n", _3gtable_size);
					error = 0;
					continue;
				}

				if (_3gtable_size > sizeof(_3g_table))
					ErrorExit(5000, "3g table buffer too small. Recompile with bigger buffer.\n");

				memcpy(_3g_table, g_dataOut2, _3gtable_size);						
				strcpy(szDataPath, "ms0:/F0/PSARDUMPER/3000_files_table.bin");
			}else
			{
				sprintf(szDataPath, "ms0:/F0/PSARDUMPER/%s", strrchr(name, '/') + 1);
			}


			//select file
			int i=0;
			for(;i<argc;i++)
				if(!strcmp(szDataPath,argv[2*i])){strcpy(szDataPath,argv[2*i+1]);break;}
			if(i==argc){error=0;continue;}


			//write it!
			printf("'%s' ", szDataPath);
/*
			if (signcheck && mode == MODE_ENCRYPT_SIGCHECK 
				&& (strcmp(name, "flash0:/kd/loadexec.prx") != 0)
				&& (strcmp(name, "flash0:/kd/loadexec_01g.prx") != 0)
				&& (strcmp(name, "flash0:/kd/loadexec_02g.prx") != 0))
			{
				pspSignCheck(g_dataOut2);
			}
*/

			if ((mode != MODE_DECRYPT) || (memcmp(g_dataOut2, "~PSP", 4) != 0))
			{
				if (strstr(szDataPath, "ipl") && (strstr(szDataPath, "2000") || strstr(szDataPath, "02h") || strstr(szDataPath, "02g")))
				{
					// IPL Pre-decryption
					cbExpanded = pspDecryptPRX(g_dataOut2, g_dataOut, cbExpanded);
					if (cbExpanded <= 0)
					{
						printf("Warning: cannot pre-decrypt 2000 IPL.\n");
					}
					else
					{
						memcpy(g_dataOut2, g_dataOut, cbExpanded);
					}							
				}
						
				if (WriteFile(szDataPath, g_dataOut2, cbExpanded) != cbExpanded)
	            {
					ErrorExit(5000, "Cannot write %s.\n", szDataPath);
					break;
				}
	                    
				printf(",saved");
			}

			if ((memcmp(g_dataOut2, "~PSP", 4) == 0) &&
				(mode == MODE_DECRYPT))
			{
				int cbDecrypted = pspDecryptPRX(g_dataOut2, g_dataOut, cbExpanded);

				// output goes back to main buffer
				// trashed 'g_dataOut2'
				if (cbDecrypted > 0)
				{
					u8* pbToSave = g_dataOut;
					int cbToSave = cbDecrypted;

					printf(",decrypted");
                            
					if ((g_dataOut[0] == 0x1F && g_dataOut[1] == 0x8B) ||
						memcmp(g_dataOut, "2RLZ", 4) == 0 || memcmp(g_dataOut, "KL4E", 4) == 0)
					{
						int cbExp = pspDecompress(g_dataOut, g_dataOut2, sizeof(g_dataOut));
						
						if (cbExp > 0)
						{
							printf(",expanded");
							pbToSave = g_dataOut2;
							cbToSave = cbExp;
						}
						else
						{
							printf("Decompress error 0x%08X\n"
								   "File will be written compressed.\n", cbExp);
						}
					}
        			
					if (WriteFile(szDataPath, pbToSave, cbToSave) != cbToSave)
					{
						ErrorExit(5000, "Error writing %s.\n", szDataPath);
					}
                    
					printf(",saved!\n");
				}
				else
				{
					
					printf(",not decrypted.\n");
					
				}
			}

			else if (strncmp(name, "ipl:", 4) == 0)
			{
				sprintf(szDataPath, "ms0:/F0/PSARDUMPER/part1_%s", szFileBase);
                        
				int cb1 = pspDecryptIPL1(g_dataOut2, g_dataOut, cbExpanded);
				if (cb1 > 0 && (WriteFile(szDataPath, g_dataOut, cb1) == cb1))
				{
					int cb2 = pspLinearizeIPL2(g_dataOut, g_dataOut2, cb1);
					sprintf(szDataPath, "ms0:/F0/PSARDUMPER/part2_%s", szFileBase);
							
					WriteFile(szDataPath, g_dataOut2, cb2);
					
					int cb3 = pspDecryptIPL3(g_dataOut2, g_dataOut, cb2);
					sprintf(szDataPath, "ms0:/F0/PSARDUMPER/part3_%s", szFileBase);
					WriteFile(szDataPath, g_dataOut, cb3);
				}
			}
		}
		/*else if (cbExpanded == 0)
		{
			printf("empty");
		}*/

		//printf("\n");
		error = 0;
		scePowerTick(0);	
	}

	sceIoClose(fd);
/*
	ExtractReboot(mode, "ms0:/F0/kd/loadexec.prx", "ms0:/F0/reboot.bin", "reboot.bin");
	ExtractReboot(mode, "ms0:/F0/kd/loadexec_01g.prx", "ms0:/F0/reboot.bin", "reboot.bin");
	ExtractReboot(mode, "ms0:/F0/kd/loadexec_02g.prx", "ms0:/F0/reboot_02g.bin", "reboot_02g.bin");
	ExtractReboot(mode, "ms0:/F0/kd/loadexec_03g.prx", "ms0:/F0/reboot_03g.bin", "reboot_03g.bin");
*/

    return 0;
}

#define argc(a) (sizeof(a)/sizeof(*(a))/2)
int main(){
	int s;
	SceUID mod;

	pspDebugScreenInit();

	if (sceKernelDevkitVersion() < 0x02070110)
	{
		ErrorExit(10000, "This program requires 2.71 or higher.\n",
			             "If you are in a cfw, please reexecute psardumper on the higher kernel.\n");
	}

	mod = LoadStartModule("libpsardumper.prx", PSP_MEMORY_PARTITION_KERNEL);
	if (mod < 0)
	{
		ErrorExit(5000, "Error 0x%08X loading/starting libpsardumper.prx.\n", mod);
	}

	mod = LoadStartModule("pspdecrypt.prx", PSP_MEMORY_PARTITION_KERNEL);
	if (mod < 0)
	{
		ErrorExit(5000, "Error 0x%08X loading/starting pspdecrypt.prx.\n", mod);
	}

	printf("Popsloader Extracter 0.02.091222 based on PSAR Dumper by PspPet\n");
	printf("IPL Decryption By Nem.\n");
	printf("2.60 - 2.80 Decryption By Dark_AleX.\n");
	printf("3.00 - 3.30 Decryption By Team Noobz.\n");
	printf("3.03 - 3.52 Decryption By Team C+D.\n");
	printf("3.60 + 3.71 + 5.00 Decryption + Recode for 2.xx+ Kernels By M33 Team.\n");
	printf("3.73 + 3.80 + 3.90 + 3.93 + 3.95 + 4.05 Decryption By RedSquirrel.\n");
	printf("4.00 Decryption By noRTU.\n");
	printf("4.01 Decryption By PSPGen.\n");
	printf("5.50 User Mode By Red Bull PSP Team.\n");
	printf("5.55 + 6.00 User Mode By Yoshihiro.\n");
	printf("6.10 User Mode By Ultradog.\n\n");

	sceIoMkdir("ms0:/seplugins", 0777);
	sceIoMkdir("ms0:/seplugins/popsloader", 0777);

	sceKernelVolatileMemLock(0, (void *)&g_dataOut2, &s);

	{	char *p401[]={
			"ms0:/F0/kd/impose.prx","ms0:/seplugins/popsloader/impose.prx",
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman401.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops401.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini401.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc401.prx",
		}; Expand("ms0:/401.PBP",argc(p401),p401);}
	{	char *p300[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman300.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops300.prx",
			"ms0:/F0/kd/meaudio.prx","ms0:/seplugins/popsloader/meaudio300.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini300.prx",
		}; Expand("ms0:/300.PBP",argc(p300),p300);}
	{	char *p301[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman301.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops301.prx",
			"ms0:/F0/kd/meaudio.prx","ms0:/seplugins/popsloader/meaudio301.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini301.prx",
		}; Expand("ms0:/301.PBP",argc(p301),p301);}
	{	char *p302[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman302.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops302.prx",
			"ms0:/F0/kd/meaudio.prx","ms0:/seplugins/popsloader/meaudio302.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini302.prx",
		}; Expand("ms0:/302.PBP",argc(p302),p302);}
	{	char *p303[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman303.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops303.prx",
			"ms0:/F0/kd/meaudio.prx","ms0:/seplugins/popsloader/meaudio303.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini303.prx",
		}; Expand("ms0:/303.PBP",argc(p303),p303);}
	{	char *p310[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman310.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops310.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini310.prx",
		}; Expand("ms0:/310.PBP",argc(p310),p310);}
	{	char *p311[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman311.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops311.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini311.prx",
		}; Expand("ms0:/311.PBP",argc(p311),p311);}
	{	char *p330[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman330.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops330.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini330.prx",
		}; Expand("ms0:/330.PBP",argc(p330),p330);}
	{	char *p340[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman340.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops340.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini340.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc340.prx",
		}; Expand("ms0:/340.PBP",argc(p340),p340);}
	{	char *p351[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman351.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops351.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini351.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc351.prx",
		}; Expand("ms0:/351.PBP",argc(p351),p351);}
	{	char *p352[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman352.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops352.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini352.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc352.prx",
		}; Expand("ms0:/352.PBP",argc(p352),p352);}
	{	char *p371[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman371.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops371.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini371.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc371.prx",
		}; Expand("ms0:/371.PBP",argc(p371),p371);}
	{	char *p372[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman372.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops372.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini372.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc372.prx",
		}; Expand("ms0:/372.PBP",argc(p372),p372);}
	{	char *p380[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman380.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops380.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini380.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc380.prx",
		}; Expand("ms0:/380.PBP",argc(p380),p380);}
	{	char *p390[]={
			"ms0:/F0/kd/popsman.prx","ms0:/seplugins/popsloader/popsman390.prx",
			"ms0:/F0/kd/pops.prx","ms0:/seplugins/popsloader/pops390.prx",
			"ms0:/F0/vsh/module/pafmini.prx","ms0:/seplugins/popsloader/pafmini390.prx",
			"ms0:/F0/vsh/module/libpspvmc.prx","ms0:/seplugins/popsloader/libpspvmc390.prx",
		}; Expand("ms0:/390.PBP",argc(p390),p390);}

	//Add what you want.

    scePowerTick(0);	
	ErrorExit(10000, "Done.\nAuto-exiting in 10 seconds.\n");
	return 0;
}
