The firmware updates also contain a similar file that can be parsed by this program.
Enjoy!
Code: Select all
/*
* PSP PSF File Parser v 0.2
*
* Copyright Chris Barrera a.k.a. Gorim
* Date : January 8 2005
*
* This source is licensed under the terms of the Academic Free License 2.0
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRBUFSZ 512
/* For endian neutrality */
u_int32_t le32(u_int32_t bits)
{
u_int8_t *bytes;
bytes = (u_int8_t*)&bits;
return(bytes[0] | (bytes[1]<<8) | (bytes[2]<<16) | (bytes[3]<<24));
}
/* For endian neutrality */
u_int16_t le16(u_int16_t bits)
{
u_int8_t *bytes;
bytes = (u_int8_t*)&bits;
return(bytes[0] | bytes[1]<<8);
}
struct PsfHdr
{
u_int8_t magic[4];
u_int8_t rfu000[4];
u_int32_t label_ptr;
u_int32_t data_ptr;
u_int32_t nsects;
};
struct PsfSec
{
u_int16_t label_off;
u_int8_t rfu001;
u_int8_t data_type; /* string=2, integer=4, binary=0 */
u_int32_t datafield_used;
u_int32_t datafield_size;
u_int32_t data_off;
};
char PsfMagic[] = "\0PSF";
char PsfDefaultFile[] = "PARAM.SFO";
int main(int argc, char *argv[])
{
FILE *PsfFile;
char *PsfFilename;
struct PsfHdr *psfheader;
struct PsfSec *psfsections, *sect;
u_int8_t *psf;
u_int8_t *psflabels;
u_int8_t *psfdata;
u_int8_t strbuf[STRBUFSZ];
int dsize, i;
PsfFilename = (argc != 2) ? PsfDefaultFile : argv[1];
if (!(PsfFile = fopen(PsfFilename, "rb")))
{
perror("File cannot be opened.");
exit(1);
}
fseek(PsfFile, 0, SEEK_END);
dsize = ftell(PsfFile);
psf = (u_int8_t*)malloc(dsize);
rewind(PsfFile);
fread(psf, dsize, 1, PsfFile);
fclose(PsfFile);
if (memcmp(PsfMagic, psf, 4))
{
printf("This file is not a PSF file ! [PSF Magic == 0x%08x]\n", *(u_int32_t*)PsfMagic);
exit(1);
}
psfheader = (struct PsfHdr*)psf;
psfsections = (struct PsfSec*)(psf + sizeof(struct PsfHdr));
psflabels = psf + le32(psfheader->label_ptr);
psfdata = psf + le32(psfheader->data_ptr);
printf("=============================================================================\n");
printf("PlayStation Portable PSF File Data\n");
printf("=============================================================================\n");
printf("\nFilename : %s\n\n", PsfFilename);
printf("Start of section labels : %2x\n", le32(psfheader->label_ptr));
printf("Start of section data : %2x\n", le32(psfheader->data_ptr));
printf("Unknown header data : %02x %02x %02x %02x\n",
psfheader->rfu000[0], psfheader->rfu000[1], psfheader->rfu000[2],
psfheader->rfu000[3]);
printf("Number of Sections : %d\n\n", le32(psfheader->nsects));
printf("Sect Loff Doff Dsiz Duse Dtyp Unkn Label Value\n");
printf("=============================================================================\n");
for (i = 0, sect = psfsections; i < le32(psfheader->nsects); i++, sect++)
{
printf(" %2d %04x %04x %04x %04x %02x %04x %-16s = ", i,
le16(sect->label_off), le32(sect->data_off), le32(sect->datafield_size),
le32(sect->datafield_used), sect->data_type, sect->rfu001,
&psflabels[le16(sect->label_off)]);
switch(sect->data_type)
{
case 2: /* string*/
/* Because the data types can be arbitrarily specified,
and we are explicitly given the data length, we should
not assume strings are NULL terminated here. Ok, they might
be anyway, but just let me be paranoid */
dsize = le32(sect->datafield_used) < STRBUFSZ ?
le32(sect->datafield_used) : STRBUFSZ-1;
strncpy(strbuf, &psfdata[le32(sect->data_off)], dsize);
strbuf[dsize] = '\0';
printf("%s\n", strbuf);
break;
case 4: /* Integer word */
printf("%d\n", le32(*(u_int32_t*)&psfdata[le32(sect->data_off)]));
break;
case 0: /* binary data ? */
printf("Binary Data\n");
break;
default: /* Dunno yet */
printf("Yet unknown. Please email save to wildwabbit@gmail.com\n");
break;
}
}
printf("=============================================================================\n");
printf("Loff = Offset of the Label Field within the Label section.\n");
printf("Doff = Offset of the Data Field within the Data section.\n");
printf("Dsiz = Size of the Data Field within the Data section.\n");
printf("Duse = Amount of the Data Field that currently contains data.\n");
printf("Dtyp = The Data Field type. 0 = Binary (?), 4 = Integer Word, 2 = String.\n");
printf("Unkn = Unknown field usage.\n\n");
return 0;
}
(1) Upped max mmap filesize for larger PARAM.SFO's. Was kinda arbitrary.
(2) Printed wrong values for string and int data types, they were swapped.
(3) Didn't verify the success of mmap. I tried to make this as portable as possible to any platform, but its only tested on MacOSX, so I better do as many sanity checks as possible.
(4) Use of mmap() wasn't portable, so I removed it and used standard file i/o routines to read in the param.sfo file data.
(5) changed fopen() mode from "r" to "rb" for non-UNIX OS's that care.