Program for parsing data in PARAM.SFO files

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Guest

Program for parsing data in PARAM.SFO files

Post by Guest »

Ok, within each savefile directory is a file called PARAM.SFO that contains interesting data. I wrote a program to parse the fields within that file and print them out. Naturally, there are still mysteries within that file.

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&#40;u_int32_t bits&#41;
&#123;
	u_int8_t *bytes;
	bytes = &#40;u_int8_t*&#41;&bits;
	return&#40;bytes&#91;0&#93; | &#40;bytes&#91;1&#93;<<8&#41; | &#40;bytes&#91;2&#93;<<16&#41; | &#40;bytes&#91;3&#93;<<24&#41;&#41;;
&#125;

/* For endian neutrality */
u_int16_t le16&#40;u_int16_t bits&#41;
&#123;
	u_int8_t *bytes;
	bytes = &#40;u_int8_t*&#41;&bits;
	return&#40;bytes&#91;0&#93; | bytes&#91;1&#93;<<8&#41;;
&#125;

struct PsfHdr
&#123;
	u_int8_t	magic&#91;4&#93;;
	u_int8_t	rfu000&#91;4&#93;;
	u_int32_t	label_ptr;
	u_int32_t	data_ptr;
	u_int32_t	nsects;
&#125;;

struct PsfSec
&#123;
	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;
&#125;;

char PsfMagic&#91;&#93; = "\0PSF";
char PsfDefaultFile&#91;&#93; = "PARAM.SFO";

int main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
	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&#91;STRBUFSZ&#93;;
	int		dsize, i;

	PsfFilename = &#40;argc != 2&#41; ? PsfDefaultFile &#58; argv&#91;1&#93;;

	if &#40;!&#40;PsfFile = fopen&#40;PsfFilename, "rb"&#41;&#41;&#41;
	&#123;
		perror&#40;"File cannot be opened."&#41;;
		exit&#40;1&#41;;
	&#125;

	fseek&#40;PsfFile, 0, SEEK_END&#41;;
	dsize = ftell&#40;PsfFile&#41;;
	psf = &#40;u_int8_t*&#41;malloc&#40;dsize&#41;;
	rewind&#40;PsfFile&#41;;
	fread&#40;psf, dsize, 1, PsfFile&#41;;
	fclose&#40;PsfFile&#41;;

	if &#40;memcmp&#40;PsfMagic, psf, 4&#41;&#41;
	&#123;
		printf&#40;"This file is not a PSF file ! &#91;PSF Magic == 0x%08x&#93;\n", *&#40;u_int32_t*&#41;PsfMagic&#41;;
		exit&#40;1&#41;;
	&#125;

	psfheader = &#40;struct PsfHdr*&#41;psf;
	psfsections = &#40;struct PsfSec*&#41;&#40;psf + sizeof&#40;struct PsfHdr&#41;&#41;;
	psflabels = psf + le32&#40;psfheader->label_ptr&#41;;
	psfdata = psf + le32&#40;psfheader->data_ptr&#41;;

	printf&#40;"=============================================================================\n"&#41;;
	printf&#40;"PlayStation Portable PSF File Data\n"&#41;;
	printf&#40;"=============================================================================\n"&#41;;
	printf&#40;"\nFilename                &#58; %s\n\n", PsfFilename&#41;;
	printf&#40;"Start of section labels &#58; %2x\n", le32&#40;psfheader->label_ptr&#41;&#41;;
	printf&#40;"Start of section data   &#58; %2x\n", le32&#40;psfheader->data_ptr&#41;&#41;;
	printf&#40;"Unknown header data     &#58; %02x %02x %02x %02x\n",
		psfheader->rfu000&#91;0&#93;, psfheader->rfu000&#91;1&#93;, psfheader->rfu000&#91;2&#93;,
		psfheader->rfu000&#91;3&#93;&#41;;
	printf&#40;"Number of Sections      &#58; %d\n\n", le32&#40;psfheader->nsects&#41;&#41;;
	printf&#40;"Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value\n"&#41;;
	printf&#40;"=============================================================================\n"&#41;;

	for &#40;i = 0, sect = psfsections; i < le32&#40;psfheader->nsects&#41;; i++, sect++&#41;
	&#123;
		printf&#40;" %2d  %04x %04x %04x %04x  %02x  %04x     %-16s = ", i,
			le16&#40;sect->label_off&#41;, le32&#40;sect->data_off&#41;, le32&#40;sect->datafield_size&#41;,
			le32&#40;sect->datafield_used&#41;, sect->data_type, sect->rfu001,
			&psflabels&#91;le16&#40;sect->label_off&#41;&#93;&#41;;

		switch&#40;sect->data_type&#41;
		&#123;
			case 2&#58;	/* 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&#40;sect->datafield_used&#41; < STRBUFSZ ?
					le32&#40;sect->datafield_used&#41; &#58; STRBUFSZ-1;
				strncpy&#40;strbuf, &psfdata&#91;le32&#40;sect->data_off&#41;&#93;, dsize&#41;;
				strbuf&#91;dsize&#93; = '\0';

				printf&#40;"%s\n", strbuf&#41;;
				break;

			case 4&#58; /* Integer word */
				printf&#40;"%d\n", le32&#40;*&#40;u_int32_t*&#41;&psfdata&#91;le32&#40;sect->data_off&#41;&#93;&#41;&#41;;
				break;

			case 0&#58; /* binary data ? */
				printf&#40;"Binary Data\n"&#41;;
				break;

			default&#58; /* Dunno yet */
				printf&#40;"Yet unknown. Please email save to [email protected]\n"&#41;;
				break;
		&#125;
	&#125;
	printf&#40;"=============================================================================\n"&#41;;
	printf&#40;"Loff = Offset of the Label Field within the Label section.\n"&#41;;
	printf&#40;"Doff = Offset of the Data Field within the Data section.\n"&#41;;
	printf&#40;"Dsiz = Size of the Data Field within the Data section.\n"&#41;;
	printf&#40;"Duse = Amount of the Data Field that currently contains data.\n"&#41;;
	printf&#40;"Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.\n"&#41;;
	printf&#40;"Unkn = Unknown field usage.\n\n"&#41;;

	return 0;
&#125;

Edits:
(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.
Last edited by Guest on Mon Apr 04, 2005 1:20 am, edited 5 times in total.
ooPo
Site Admin
Posts: 2023
Joined: Sat Jan 17, 2004 9:56 am
Location: Canada
Contact:

Post by ooPo »

Pretty!
Guest

Sample program outputs from various save games - Mina No Gol

Post by Guest »

From the PSP memstick:/PSP/SAVEDATA/UCJS10001 (savegame dir)

Running the program produces this output:

Code: Select all

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; PARAM.SFO

Start of section labels &#58; 94
Start of section data   &#58; 108
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 8

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0002  02  0004     CATEGORY         = MS
  1  0009 0004 0004 0004  04  0004     PARENTAL_LEVEL   = 1
  2  0018 0008 0400 0001  02  0004     SAVEDATA_DETAIL  = 
  3  0028 0408 0040 000a  02  0004     SAVEDATA_DIRECTORY = UCJS10001
  4  003b 0448 0c60 0c60  00  0004     SAVEDATA_FILE_LIST = Binary Data
  5  004e 10a8 0080 0080  00  0004     SAVEDATA_PARAMS  = Binary Data
  6  005e 1128 0080 0001  02  0004     SAVEDATA_TITLE   = 
  7  006d 11a8 0080 0029  02  0004     TITLE            = ã¿ããªã®ï¼§ï¼¯ï¼¬ï¼¦ ãã¼ã¿ãã«
=============================================================================
Loff = Offset of the Label Field within the Label section.
Doff = Offset of the Data Field within the Data section.
Dsiz = Size of the Data Field within the Data section.
Duse = Amount of the Data Field that currently contains data.
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.
Unkn = Unknown field usage.
Here is a basic hexdump -C of the same file:

Code: Select all

00000000  00 50 53 46 01 01 00 00  94 00 00 00 08 01 00 00  |.PSF............|
00000010  08 00 00 00 00 00 04 02  02 00 00 00 04 00 00 00  |................|
00000020  00 00 00 00 09 00 04 04  04 00 00 00 04 00 00 00  |................|
00000030  04 00 00 00 18 00 04 02  01 00 00 00 00 04 00 00  |................|
00000040  08 00 00 00 28 00 04 02  0a 00 00 00 40 00 00 00  |....&#40;.......@...|
00000050  08 04 00 00 3b 00 04 00  60 0c 00 00 60 0c 00 00  |....;...`...`...|
00000060  48 04 00 00 4e 00 04 00  80 00 00 00 80 00 00 00  |H...N...........|
00000070  a8 10 00 00 5e 00 04 02  01 00 00 00 80 00 00 00  |....^...........|
00000080  28 11 00 00 6d 00 04 02  29 00 00 00 80 00 00 00  |&#40;...m...&#41;.......|
00000090  a8 11 00 00 43 41 54 45  47 4f 52 59 00 50 41 52  |....CATEGORY.PAR|
000000a0  45 4e 54 41 4c 5f 4c 45  56 45 4c 00 53 41 56 45  |ENTAL_LEVEL.SAVE|
000000b0  44 41 54 41 5f 44 45 54  41 49 4c 00 53 41 56 45  |DATA_DETAIL.SAVE|
000000c0  44 41 54 41 5f 44 49 52  45 43 54 4f 52 59 00 53  |DATA_DIRECTORY.S|
000000d0  41 56 45 44 41 54 41 5f  46 49 4c 45 5f 4c 49 53  |AVEDATA_FILE_LIS|
000000e0  54 00 53 41 56 45 44 41  54 41 5f 50 41 52 41 4d  |T.SAVEDATA_PARAM|
000000f0  53 00 53 41 56 45 44 41  54 41 5f 54 49 54 4c 45  |S.SAVEDATA_TITLE|
00000100  00 54 49 54 4c 45 00 00  4d 53 00 00 01 00 00 00  |.TITLE..MS......|
00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000510  55 43 4a 53 31 30 30 30  31 00 00 00 00 00 00 00  |UCJS10001.......|
00000520  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000550  d0 64 69 08 00 00 00 00  00 00 00 00 00 00 00 00  |.di.............|
00000560  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000570  44 41 54 41 2e 42 49 4e  00 00 00 00 00 63 34 44  |DATA.BIN.....c4D|
00000580  55 0a 74 a6 d4 cc 30 af  f7 6a 51 ba 17 00 00 00  |U.t...0..jQ.....|
00000590  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000011b0  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000011c0  f2 1d 8f 8a 80 ed f2 a4  dd 85 63 a7 a7 93 b6 30  |..........c....0|
000011d0  a5 0c ba ad 7f 62 77 33  c3 98 95 ef 97 4c d3 42  |.....bw3.....L.B|
000011e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000012b0  e3 81 bf e3 82 93 e3 81  aa e3 81 ae ef bc a7 ef  |................|
000012c0  bc af ef bc ac ef bc a6  20 e3 83 9d e3 83 bc e3  |........ .......|
000012d0  82 bf e3 83 96 e3 83 ab  00 00 00 00 00 00 00 00  |................|
000012e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001330
Last edited by Guest on Sat Jan 08, 2005 10:11 pm, edited 1 time in total.
Guest

More savefile...this time from Oopo's bane

Post by Guest »

Not just savegames PARAM.SFO can be read. There is a similar file, probably by the same name, included in the "Oopo's Bane" firmware download package.

Here is output from the program:

Code: Select all

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; ooposbane.sfo

Start of section labels &#58; b4
Start of section data   &#58; 11c
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 10

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0004  04  0004     BOOTABLE         = 1
  1  0009 0004 0004 0003  02  0004     CATEGORY         = MG
  2  0012 0008 0010 000b  02  0004     DISC_ID          = ABCD-00000
  3  001a 0018 0008 0005  02  0004     DISC_VERSION     = 1.00
  4  0027 0020 0040 0001  02  0004     DRIVER_PATH      = 
  5  0033 0060 0004 0003  02  0004     LANGUAGE         = JP
  6  003c 0064 0004 0004  04  0004     PARENTAL_LEVEL   = 1
  7  004b 0068 0008 0005  02  0004     PSP_SYSTEM_VER   = 1.00
  8  005a 0070 0004 0004  04  0004     REGION           = 32768
  9  0061 0074 0080 000f  02  0004     TITLE            = APP00&#40;balloon&#41;
=============================================================================
Loff = Offset of the Label Field within the Label section.
Doff = Offset of the Data Field within the Data section.
Dsiz = Size of the Data Field within the Data section.
Duse = Amount of the Data Field that currently contains data.
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.
Unkn = Unknown field usage.
And of course, the basic hexdump -C of the same file:

Code: Select all

00000000  00 50 53 46 01 01 00 00  b4 00 00 00 1c 01 00 00  |.PSF............|
00000010  0a 00 00 00 00 00 04 04  04 00 00 00 04 00 00 00  |................|
00000020  00 00 00 00 09 00 04 02  03 00 00 00 04 00 00 00  |................|
00000030  04 00 00 00 12 00 04 02  0b 00 00 00 10 00 00 00  |................|
00000040  08 00 00 00 1a 00 04 02  05 00 00 00 08 00 00 00  |................|
00000050  18 00 00 00 27 00 04 02  01 00 00 00 40 00 00 00  |....'.......@...|
00000060  20 00 00 00 33 00 04 02  03 00 00 00 04 00 00 00  | ...3...........|
00000070  60 00 00 00 3c 00 04 04  04 00 00 00 04 00 00 00  |`...<...........|
00000080  64 00 00 00 4b 00 04 02  05 00 00 00 08 00 00 00  |d...K...........|
00000090  68 00 00 00 5a 00 04 04  04 00 00 00 04 00 00 00  |h...Z...........|
000000a0  70 00 00 00 61 00 04 02  0f 00 00 00 80 00 00 00  |p...a...........|
000000b0  74 00 00 00 42 4f 4f 54  41 42 4c 45 00 43 41 54  |t...BOOTABLE.CAT|
000000c0  45 47 4f 52 59 00 44 49  53 43 5f 49 44 00 44 49  |EGORY.DISC_ID.DI|
000000d0  53 43 5f 56 45 52 53 49  4f 4e 00 44 52 49 56 45  |SC_VERSION.DRIVE|
000000e0  52 5f 50 41 54 48 00 4c  41 4e 47 55 41 47 45 00  |R_PATH.LANGUAGE.|
000000f0  50 41 52 45 4e 54 41 4c  5f 4c 45 56 45 4c 00 50  |PARENTAL_LEVEL.P|
00000100  53 50 5f 53 59 53 54 45  4d 5f 56 45 52 00 52 45  |SP_SYSTEM_VER.RE|
00000110  47 49 4f 4e 00 54 49 54  4c 45 00 00 01 00 00 00  |GION.TITLE......|
00000120  4d 47 00 00 41 42 43 44  2d 30 30 30 30 30 00 00  |MG..ABCD-00000..|
00000130  00 00 00 00 31 2e 30 30  00 00 00 00 00 00 00 00  |....1.00........|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000170  00 00 00 00 00 00 00 00  00 00 00 00 4a 50 00 00  |............JP..|
00000180  01 00 00 00 31 2e 30 30  00 00 00 00 00 80 00 00  |....1.00........|
00000190  41 50 50 30 30 28 62 61  6c 6c 6f 6f 6e 29 00 00  |APP00&#40;balloon&#41;..|
000001a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000210
Last edited by Guest on Sat Jan 08, 2005 10:11 pm, edited 1 time in total.
Guest

Post by Guest »

Now for some more commentary,

The files in question appear to contain paramters/environment that are relevant to the respective functions of the "saves". In the case of hot shotz golf, that was a bonafide savegame. In the case of the firmware update, its more relevant to the act of updating firmware.

There are still some fields of the header and sections that I haven't figured out.

Also, especially in the hot shots golf save, there are from data fields that appear to contain, not just specific basic data types, but extended data types.

Given the heavy usage of offsets and strings in these files, it offers interesting possibilities for naughty tinkering.
ooPo
Site Admin
Posts: 2023
Joined: Sat Jan 17, 2004 9:56 am
Location: Canada
Contact:

Post by ooPo »

ooposbane.sfo

I like it. :)
Guest

Ridge Racers

Post by Guest »

Here is a savegame, from Ridge Racers, which has much more in terms of embedded data. For instance. DATA.BIN is seen in the hexdump, but it isn't seen by the program because it can't understand the huge data blob that happens to contain that string.

Also, some of the string data is in Japanese. You should be able to see some Kanji and Katakna text. You may need to set UTF-8 encoding in your browers to see it properly.

Here is the PARAM.SFO parsing:

Code: Select all

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; PARAM.SFO

Start of section labels &#58; 94
Start of section data   &#58; 108
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 8

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0002  02  0004     CATEGORY         = MS
  1  0009 0004 0004 0004  04  0004     PARENTAL_LEVEL   = 1
  2  0018 0008 0400 0068  02  0004     SAVEDATA_DETAIL  = &#12300;&#12522;&#12483;&#12472;&#12524;&#12540;&#12469;&#12540;&#12474;&#12301;&#12466;&#12540;&#12512;&#12487;&#12540;&#12479;
&#12503;&#12524;&#12452;&#12516;&#12540;&#12493;&#12540;&#12512;&#65306;XEVIOUS
&#36208;&#34892;&#36317;&#38626;&#65306;0km

  3  0028 0408 0040 000d  02  0004     SAVEDATA_DIRECTORY = ULJS00001000
  4  003b 0448 0c60 0c60  00  0004     SAVEDATA_FILE_LIST = Binary Data
  5  004e 10a8 0080 0080  00  0004     SAVEDATA_PARAMS  = Binary Data
  6  005e 1128 0080 0013  02  0004     SAVEDATA_TITLE   = &#12466;&#12540;&#12512;&#12487;&#12540;&#12479;
  7  006d 11a8 0080 0019  02  0004     TITLE            = &#12522;&#12483;&#12472;&#12524;&#12540;&#12469;&#12540;&#12474;
=============================================================================
Loff = Offset of the Label Field within the Label section.
Doff = Offset of the Data Field within the Data section.
Dsiz = Size of the Data Field within the Data section.
Duse = Amount of the Data Field that currently contains data.
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.
Unkn = Unknown field usage.
And of course, the hexdump:

Code: Select all

00000000  00 50 53 46 01 01 00 00  94 00 00 00 08 01 00 00  |.PSF............|
00000010  08 00 00 00 00 00 04 02  02 00 00 00 04 00 00 00  |................|
00000020  00 00 00 00 09 00 04 04  04 00 00 00 04 00 00 00  |................|
00000030  04 00 00 00 18 00 04 02  68 00 00 00 00 04 00 00  |........h.......|
00000040  08 00 00 00 28 00 04 02  0d 00 00 00 40 00 00 00  |....&#40;.......@...|
00000050  08 04 00 00 3b 00 04 00  60 0c 00 00 60 0c 00 00  |....;...`...`...|
00000060  48 04 00 00 4e 00 04 00  80 00 00 00 80 00 00 00  |H...N...........|
00000070  a8 10 00 00 5e 00 04 02  13 00 00 00 80 00 00 00  |....^...........|
00000080  28 11 00 00 6d 00 04 02  19 00 00 00 80 00 00 00  |&#40;...m...........|
00000090  a8 11 00 00 43 41 54 45  47 4f 52 59 00 50 41 52  |....CATEGORY.PAR|
000000a0  45 4e 54 41 4c 5f 4c 45  56 45 4c 00 53 41 56 45  |ENTAL_LEVEL.SAVE|
000000b0  44 41 54 41 5f 44 45 54  41 49 4c 00 53 41 56 45  |DATA_DETAIL.SAVE|
000000c0  44 41 54 41 5f 44 49 52  45 43 54 4f 52 59 00 53  |DATA_DIRECTORY.S|
000000d0  41 56 45 44 41 54 41 5f  46 49 4c 45 5f 4c 49 53  |AVEDATA_FILE_LIS|
000000e0  54 00 53 41 56 45 44 41  54 41 5f 50 41 52 41 4d  |T.SAVEDATA_PARAM|
000000f0  53 00 53 41 56 45 44 41  54 41 5f 54 49 54 4c 45  |S.SAVEDATA_TITLE|
00000100  00 54 49 54 4c 45 00 00  4d 53 00 00 01 00 00 00  |.TITLE..MS......|
00000110  e3 80 8c e3 83 aa e3 83  83 e3 82 b8 e3 83 ac e3  |................|
00000120  83 bc e3 82 b5 e3 83 bc  e3 82 ba e3 80 8d e3 82  |................|
00000130  b2 e3 83 bc e3 83 a0 e3  83 87 e3 83 bc e3 82 bf  |................|
00000140  0a e3 83 97 e3 83 ac e3  82 a4 e3 83 a4 e3 83 bc  |................|
00000150  e3 83 8d e3 83 bc e3 83  a0 ef bc 9a 58 45 56 49  |............XEVI|
00000160  4f 55 53 0a e8 b5 b0 e8  a1 8c e8 b7 9d e9 9b a2  |OUS.............|
00000170  ef bc 9a 30 6b 6d 0a 00  00 00 00 00 00 00 00 00  |...0km..........|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000510  55 4c 4a 53 30 30 30 30  31 30 30 30 00 00 00 00  |ULJS00001000....|
00000520  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000550  48 24 6b 08 00 00 00 00  00 00 00 00 00 00 00 00  |H$k.............|
00000560  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000570  44 41 54 41 2e 42 49 4e  00 00 00 00 00 d7 44 a4  |DATA.BIN......D.|
00000580  a2 d4 79 79 33 79 30 74  c8 1d 1a 41 fa 00 00 00  |..yy3y0t...A....|
00000590  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000011b0  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000011c0  47 16 b8 45 53 10 f0 3a  69 e8 82 d2 38 17 20 fd  |G..ES..&#58;i...8. .|
000011d0  64 3e 2b 3d e3 76 80 c2  09 50 3c 11 df 8d 90 3f  |d>+=.v...P<....?|
000011e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001230  e3 82 b2 e3 83 bc e3 83  a0 e3 83 87 e3 83 bc e3  |................|
00001240  82 bf 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00001250  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000012b0  e3 83 aa e3 83 83 e3 82  b8 e3 83 ac e3 83 bc e3  |................|
000012c0  82 b5 e3 83 bc e3 82 ba  00 00 00 00 00 00 00 00  |................|
000012d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001330
beatwho
Posts: 28
Joined: Wed Dec 15, 2004 4:58 pm

Post by beatwho »

so i tried to get it working, copied the data into a psp.c
make psp
ran it..

Seg fault?

tried it with another game... same thing

what am I doing wrong?

edit: removed links
Last edited by beatwho on Sun Jan 09, 2005 9:25 pm, edited 1 time in total.
Guest

Post by Guest »

I tried your dokodemo save and it worked fine for me.

I haven't tested this on platforms over than Mac OSX, but its written so that it should work with no problem anywhere POSIX. Anyhow please let me know the following:

1. Are there any messages (warnings, etc...) printed when you compile it ?
2. Does the program manage to print ANYTHING when its run, besides segfault ?
3. Anyhow, I made one modification to the program to check if the mmap call succeeds and print a message if it doesn't. Otherwise, if it fails, a segfault will occur for sure (though dunno why it should fail). Anyhow, try recopying and rerunning the program and let me know if anything gets printed out at all.
beatwho
Posts: 28
Joined: Wed Dec 15, 2004 4:58 pm

Post by beatwho »

[root@heis psp]# make psp
cc psp.c -o psp
[root@heis psp]# ls
PARAM.SFO psp psp.c
[root@heis psp]# ./psp
mmap failed!: Invalid argument
[root@heis psp]# uname -a
Linux heis.nakedinjapan.net 2.4.27 #1 Wed Nov 17 20:29:58 JST 2004 i686 i686 i386 GNU/Linux

well there ya go, looks like it opens the file fine then mmap fails. I might go read the man page for mmap since i've never even heard of it before :)

Thanks

edit: I changed the mmap stuff to fopen/fread and it worked ^_^
Guest

Post by Guest »

beatwho wrote:
edit: I changed the mmap stuff to fopen/fread and it worked ^_^
Yeah, thats what I was going to do if it turned out to be mmap that was the problem. I am a mmap-kinda-guy which is why I used it, but there is no reason its a must.

Later when I get back from Akihabara I will throw out the mmap stuff and replace it with:

fopen(...)
fseek(...,SEEK_END)
fsize = ftell()
frewind(...)
psf = (u_int8_t*)calloc(fsize);
fread(psf,...,fsize,...)
fclose(...)

Which should make it more portable.

Thanks for testing it out!
Guest

Post by Guest »

Ok, I updated the program listing at the top of this thread with the newest version that removes the mmap() and replaces it with standard file i/o routines to accomplish the same thing. It should now be more portable.
annerajb
Posts: 40
Joined: Thu Mar 31, 2005 6:16 am

Post by annerajb »

this my seen like a noob question but. how the you compile this program. and what is made in c c++ . btw i have visual basic .net
DBG
Posts: 12
Joined: Mon Mar 28, 2005 9:08 am

Post by DBG »

You will need a C compilier, personally I use www.cygwin.com or www.mingw.org. There are lots of how-to's out there, but if you need more help just ask. I don't believe VB can handle the file, but if you have access to Visual Studio you should be able to copy the text into a .c file and build that.
Deathbringer
Posts: 11
Joined: Fri Apr 01, 2005 4:10 am

Post by Deathbringer »

Can someone compile it for me? Since my good pc are screved up and this machine has Admin lock so i cant install anything...
Grover
Posts: 50
Joined: Wed Feb 23, 2005 3:13 am

Post by Grover »

Wondering about these bin files - assuming they are binary files. Is it possible these are executed mips binaries? Or (more likely) specific binary data dictating the way background is drawn, and other effects (sound/music?).
Bye.
XenuPSP
Posts: 3
Joined: Mon Apr 04, 2005 12:48 am

Post by XenuPSP »

FYI--

I've got this compiled and running on my WinXP box using MinGW tools. Running it against an Untold Legends .SFO, I noticed a character in the data section was being gobbled up. I corrected it by changing the fopen() mode from "r" to "rb".
Guest

Post by Guest »

XenuPSP wrote:FYI--

I've got this compiled and running on my WinXP box using MinGW tools. Running it against an Untold Legends .SFO, I noticed a character in the data section was being gobbled up. I corrected it by changing the fopen() mode from "r" to "rb".
Thanks for the update, I will correct the source.

Note, UNIX ignores "b" typically because there is no difference between text and binary data during file I/O, but dos/win implementations of fopen() in the C library may make such a distinction.
LiquidIce
Posts: 55
Joined: Mon Apr 04, 2005 1:15 am
Contact:

Post by LiquidIce »

This is good stuff gorim, thanks!

I compiled this under WinXP using cygwin, worked flawlessly.

Here is the output of some of my game saves if anyone is intrested:

Code: Select all

NFS Underground&#58;

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; PARAM.SFO

Start of section labels &#58; 94
Start of section data   &#58; 108
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 8

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0002  02  0004     CATEGORY         = MS
  1  0009 0004 0004 0004  04  0004     PARENTAL_LEVEL   = 3
  2  0018 0008 0400 0001  02  0004     SAVEDATA_DETAIL  = 
  3  0028 0408 0040 000d  02  0004     SAVEDATA_DIRECTORY = ULUS10007001
  4  003b 0448 0c60 0c60  00  0004     SAVEDATA_FILE_LIST = Binary Data
  5  004e 10a8 0080 0080  00  0004     SAVEDATA_PARAMS  = Binary Data
  6  005e 1128 0080 0007  02  0004     SAVEDATA_TITLE   = LIQUID
  7  006d 11a8 0080 0025  02  0004     TITLE            = NEED FOR SPEED™ UNDERGROUND RIVALS
=============================================================================
Loff = Offset of the Label Field within the Label section.
Doff = Offset of the Data Field within the Data section.
Dsiz = Size of the Data Field within the Data section.
Duse = Amount of the Data Field that currently contains data.
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.
Unkn = Unknown field usage.



Code: Select all

Untold Legends

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; PARAM.SFO

Start of section labels &#58; 94
Start of section data   &#58; 108
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 8

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0002  02  0004     CATEGORY         = MS
  1  0009 0004 0004 0004  04  0004     PARENTAL_LEVEL   = 5
  2  0018 0008 0400 002e  02  0004     SAVEDATA_DETAIL  = The City of Aven
Search the Secret Catacombs
  3  0028 0408 0040 000e  02  0004     SAVEDATA_DIRECTORY = LUS100030000
  4  003b 0448 0c60 0c60  00  0004     SAVEDATA_FILE_LIST = Binary Data
  5  004e 10a8 0080 0080  00  0004     SAVEDATA_PARAMS  = Binary Data
  6  005e 1128 0080 0018  02  0004     SAVEDATA_TITLE   = IQUIDICE <Berserker> 3
  7  006d 11a8 0080 0029  02  0004     TITLE            = ntold Legends&#58; Brotherhood of the Blade
=============================================================================
Loff = Offset of the Label Field within the Label section.
Doff = Offset of the Data Field within the Data section.
Dsiz = Size of the Data Field within the Data section.
Duse = Amount of the Data Field that currently contains data.
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.
Unkn = Unknown field usage.

Code: Select all

Dynasty Warriors

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; PARAM.SFO

Start of section labels &#58; 94
Start of section data   &#58; 108
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 8

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0002  02  0004     CATEGORY         = MS
  1  0009 0004 0004 0004  04  0004     PARENTAL_LEVEL   = 5
  2  0018 0008 0400 0071  02  0004     SAVEDATA_DETAIL  = The Battlefield has been shifted to
the "PSP"!
Join the fight for supremacy now and become a DYNASTY WARRIOR! 
  3  0028 0408 0040 000d  02  0004     SAVEDATA_DIRECTORY = US10004000
  4  003b 0448 0c60 0c60  00  0004     SAVEDATA_FILE_LIST = Binary Data
  5  004e 10a8 0080 0080  00  0004     SAVEDATA_PARAMS  = Binary Data
  6  005e 1128 0080 000a  02  0004     SAVEDATA_TITLE   = me data
  7  006d 11a8 0080 0011  02  0004     TITLE            = NASTY WARRIORS
=============================================================================
Loff = Offset of the Label Field within the Label section.
Doff = Offset of the Data Field within the Data section.
Dsiz = Size of the Data Field within the Data section.
Duse = Amount of the Data Field that currently contains data.
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.
Unkn = Unknown field usage.

Just so that we're all on the same page. Are you all suggesting we may be able to modify the saved game files to inject our own code?
Guest

Post by Guest »

LiquidIce wrote:Just so that we're all on the same page. Are you all suggesting we may be able to modify the saved game files to inject our own code?
That possibility always exists wherever file i/o is done and we can modify the files being read.

However, as shown in another thread on manipulating the .SFO file data, modifications can even be used to probe and display internal memory data, which in itself is a very important ability. Especially since we are still far from being able to inject code.
ModernRonin
Posts: 10
Joined: Sat May 07, 2005 5:19 pm
Location: Colorado
Contact:

Port to Win98 done.

Post by ModernRonin »

I added some typedefs to your code to make this compile under Visual C++ 6.0 on Win98. Three typedefs:

Code: Select all

// Some data type definitions for Intel Doze platforms, 2005/05/06, bwc
typedef unsigned int u_int32_t;
typedef unsigned short int u_int16_t ;
typedef unsigned char u_int8_t;
And I had to cast some pointers explicitly under case 2 to make the compiler quit whining:

Code: Select all

strncpy&#40;&#40;char *&#41;strbuf, &#40;const char *&#41;&psfdata&#91;le32&#40;sect->data_off&#41;&#93;, dsize&#41;;
In any event, it compiles and seems to work. Here's the output of running it the on PARAM.SFO inside Sony's Upgrade to 1.5 EBOOT.PBP:

Code: Select all

=============================================================================
PlayStation Portable PSF File Data
=============================================================================

Filename                &#58; PARAM.SFO

Start of section labels &#58; 104
Start of section data   &#58; 18c
Unknown header data     &#58; 01 01 00 00
Number of Sections      &#58; 15

Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value
=============================================================================
  0  0000 0000 0004 0004  04  0004     BOOTABLE         = 1
  1  0009 0004 0004 0003  02  0004     CATEGORY         = MG
  2  0012 0008 0008 0005  02  0004     DISC_VERSION     = 1.00
  3  001f 0010 0004 0004  04  0004     PARENTAL_LEVEL   = 1
  4  002e 0014 0004 0004  04  0004     REGION           = 32768
  5  0035 0018 0080 0017  02  0004     TITLE            = PSP_äó Update ver 1.
  6  003b 0098 0080 0023  02  0004     TITLE_0          = PSP_äó ¶éó¶ââ¶âù¶âç¶
  7  0043 0118 0080 001e  02  0004     TITLE_2          = Mise +á jour PSP_äó
  8  004b 0198 0080 0023  02  0004     TITLE_3          = Actualizaci+¦n de PS
  9  0053 0218 0080 0020  02  0004     TITLE_4          = PSP_äó-Aktualisierun_
 10  005b 0298 0080 0025  02  0004     TITLE_5          = Aggiornamento della _
ver. 1.50                                                                     _
 11  0063 0318 0080 001a  02  0004     TITLE_6          = PSP_äó-update versie_
 12  006b 0398 0080 001f  02  0004     TITLE_7          = Actualiza+º+úo PSP_ä_
 13  0073 0418 0080 0029  02  0004     TITLE_8          = -P-_-+-+-_-+-¦-+-+-¦_
 14  007b 0498 0008 0005  02  0004     UPDATER_VER      = 1.50                _
============================================================================= _
Loff = Offset of the Label Field within the Label section.                    _
Doff = Offset of the Data Field within the Data section.                      _
Dsiz = Size of the Data Field within the Data section.                        _
Duse = Amount of the Data Field that currently contains data.                 _
Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String.     _
Unkn = Unknown field usage.                                                   _
Source code and a compiled executable are available at the URL in my signature. Though if you're smart you'll compile it yourself - running random .EXE files off the net is a real, real stupid thing to do.
Guest

Post by Guest »

Hey thanks for the update on letting people know how they can compile it on win98! Do newer windows platforms understand the u_intX_t types ? Or is that just a GCC thing ?

The reason I stuck with the u_intX_t types is to guarantee hardware neutrality as much as possible, and to be as specific as possible in how large struct members in the file are.

I may merge this in to the main PARAM.SFO source via #ifdefs platform checks if there is enough demand for win98, or I can just let you maintain that variant of the source.
ModernRonin
Posts: 10
Joined: Sat May 07, 2005 5:19 pm
Location: Colorado
Contact:

Post by ModernRonin »

Hey thanks for the update on letting people know how they can compile it on win98!

I'm kinda curious if my executable works under 2k or XP. Actually, I'm curious if it even works on someone else's 98 box. For all I know it may depend on some weirdo DLL that only I have.

Do newer windows platforms understand the u_intX_t types ? Or is that just a GCC thing ?

I don't know. We have a couple of people here who seem to have VC++ 7.0 (.NET edition or something), maybe one of them can try and compile it and tell us.

The reason I stuck with the u_intX_t types is to guarantee hardware neutrality as much as possible, and to be as specific as possible in how large struct members in the file are.

Yeah, I think that's a good thing. That's why I put in typedefs instead of just search and replacing the code. Actually, at first I tried to make it even simpler, using #defines. But that breaks some things. The compiler doesn't seem to be able to handle casts or variable declarations with a #defined type. Don't ask me why, I have no idea...

I may merge this in to the main PARAM.SFO source via #ifdefs platform checks if there is enough demand for win98, or I can just let you maintain that variant of the source.

Probably best to merge it into the main source. I'm not sure what symbol you can check to determine if you're on a Win9X box, though... maybe there's some OS_VER() macro that I don't know about.

Ah, here we go... http://softwareforums.intel.com/ids/boa ... ge.id=1811

Looks like you can check #if _MSC_VER == 1200. That's the giveaway that you're working with Visual C++ 6.0, which is the Win98, circa 1998 version of VC++.
Last edited by ModernRonin on Sun May 08, 2005 5:22 pm, edited 1 time in total.
MelGibson
Posts: 58
Joined: Sun Apr 10, 2005 10:19 pm

Post by MelGibson »

Short Info: Even though it was compiled on and for win98 the program runs flawless on a win2000 /SP4 box i tested.
ModernRonin
Posts: 10
Joined: Sat May 07, 2005 5:19 pm
Location: Colorado
Contact:

Post by ModernRonin »

Short Info: Even though it was compiled on and for win98 the program runs flawless on a win2000 /SP4 box i tested.

Sweet! Thanks, Mel.
larox
Posts: 2
Joined: Mon Jul 04, 2005 4:39 pm
Location: Singapore

questions

Post by larox »

hey guys, can I ask you all some questions?
From the above posts, there is this u_int32_t thing...
I don't know what is it for, can you guys tell me?
is u_int32_t same as uint32_t ? And what is uint32_t used for?
Sorry for the questions, I am new to software development.
Thanks
Never compare N.A with Turbo cars because they are of different classes~
Guest

Post by Guest »

u_int32_t == unsigned integer 32 bit type.

uint32_t is almost certainly the same thing, just without an underscore.

Is it quite common for people to use typedef's or #define's in order to make such types less awkward. Also, different compilers might define them different ways. I really don't know if this is a compiler implementation-dependant issue, but it appears to be.

In your case, I don't really know if uint32_t is a compiler defined type, a standard #include defined type, or is in some user created source file. Nor would I know if it is #define'd or typedef'ed in the include file if that was the location. Check your compiler's manual.

Anyhow, as I mentioned, the reason for being specific, is that things such as "long" and "int" are actually vague with respect to the size of the type in terms of bits - they are hardware platform dependant.
larox
Posts: 2
Joined: Mon Jul 04, 2005 4:39 pm
Location: Singapore

thank you

Post by larox »

thanks alot for help. i am actually intending to do up my project which i think might require this uint32_t data type for the assigning of static ip address.

good day.~
Never compare N.A with Turbo cars because they are of different classes~
LanThief
Posts: 1
Joined: Wed Jan 18, 2006 3:12 am
Location: Austin, TX
Contact:

Python port of PARAM.SFO reader

Post by LanThief »

I was searching on PARAM.SFO files when I came across this thread, and found this C example very helpful. Thanks Chris Barrera for the code example. I do most of my game development in Python so after using this C example last night, I took a crack at it in Python for anyone interested.

Yes, there are more mysteries to uncover and so there will be more edits to come as we all contribute to the C example.

Cheers !

Code: Select all

"""
    Many Thanks to Chris Barrera for the C example that was used in converting
    over to python.  I tried to keep it as close to the C example so people can
    follow them both.  It could be written a little cleaner.  Please feel free &#58;&#41;

    /* 
     * PSP PSF File Parser v 0.2 
     * 
     * Copyright Chris Barrera a.k.a. Gorim 
     * Date  &#58; January 8 2005 
     * 
     * This source is licensed under the terms of the Academic Free License 2.0 
     * 
     */

    Python Conversion by&#58; Chris Kreager a.k.a LanThief
    Date&#58; January 17, 2006
"""

#Extra Hex Tool&#58; Start------------------------------------------------------------------
"""
    Here are some extra functions I use for hex conversions
    You may want to replace them with your own.
    I usually import these from a separate module, but I cut
    and pasted them here so the example could work as is.
"""

def str2hex&#40;s,size=8&#41;&#58;
    "String converter to hex"
    if &#40;len&#40;s&#41;*size&#41; <= 32&#58;    h = 0x0
    else&#58;                      h = 0x0L
    for c in s&#58;
        h = &#40;h << size&#41; | ord&#40;c&#41;
    return h

def hex2hexList&#40;h,size=8,reverse=True&#41;&#58;
    "hex converter to hex list"
    return hex2hexList_charList&#40;h,size,reverse,False&#41;

def hex2hexList_charList&#40;h,size=8,reverse=True,ischr=True&#41;&#58;
    "hex converter to either chr list or hex list"
    l = &#91;&#93;
    if h == 0x0&#58;
        if ischr&#58; l.append&#40;chr&#40;h&#41;&#41;
        else&#58; l.append&#40;h&#41;
        return l
    while h&#58;
        _h = &#40;h & mask_bit&#40;size&#41;&#41;
        if ischr&#58; horc = chr&#40;_h&#41;
        else&#58; horc = _h
        l.append&#40;horc&#41;
        h = &#40;h >> size&#41;
    if reverse&#58;l.reverse&#40;&#41;
    return l

def str2hexList&#40;s, size = 8, reverse=True&#41;&#58;
    "String converter to hex list"
    return hex2hexList&#40; str2hex&#40;s&#41;, size, reverse &#41;

def mask_bit&#40;size=8&#41;&#58;
    if size > 32&#58;   return &#40;0x1L << size&#41; - &#40;0x1&#41;
    else&#58;           return &#40;0x1  << size&#41; - &#40;0x1&#41;
    
#Extra Hex Tool&#58; End------------------------------------------------------------------


#Example Python Code&#58; Start--------------------------------------------------------
"""
    Below is a quick python like equivalent to the C example.
    I put this together last night for myself and any of you that 
    might like to try your hand with this in Python

    Cheers,
    - [email protected]
"""
import sys

PsfMagic = "\0PSF"
PsfDefaultFile = "PARAM.SFO"


def le32&#40;bits&#41;&#58;
    bytes = str2hexList&#40;bits&#41;
    result = 0x0
    offset = 0
    for byte in bytes&#58;
        result |= byte << offset
        offset +=8
    return result
##    # IndexError on zero bits - removed code
##    return &#40;bytes&#91;0&#93; | &#40;bytes&#91;1&#93;<<8&#41; | &#40;bytes&#91;2&#93;<<16&#41; | &#40;bytes&#91;3&#93;<<24&#41;&#41;  

def le16&#40;bits&#41;&#58;
    bytes = str2hexList&#40;bits&#41;
    if len&#40;bytes&#41; > 1&#58;
        return &#40;bytes&#91;0&#93; | bytes&#91;1&#93;<<8&#41;
    return &#40;bytes&#91;0&#93; | 0x0<<8&#41;

class PsfHdr&#58;
    size = 20
    def __init__&#40;self, bits&#41;&#58;
        self.size = 20
        self.data = bits&#91;&#58;self.size&#93;
        self.magic = str2hexList&#40; bits&#91;&#58;4&#93; &#41;
        self.rfu000 = str2hexList&#40; bits&#91;4&#58;8&#93; &#41;
        self.label_ptr = bits&#91;8&#58;12&#93;
        self.data_ptr = bits&#91;12&#58;16&#93;
        self.nsects = bits&#91;16&#58;20&#93;

    def __len__&#40;self&#41;&#58;
        return self.size

class PsfSec&#58;
    size = 16
    def __init__&#40;self, bits&#41;&#58;
        self.size = 16
        self.data = bits&#91;&#58;self.size&#93;
        self.label_off = bits&#91;&#58;2&#93;
        self.rfu001 = bits&#91;2&#58;3&#93;
        self.data_type = str2hex&#40;bits&#91;3&#58;4&#93;&#41; # string=2, integer=4, binary=0
        self.datafield_used = bits&#91;4&#58;8&#93;
        self.datafield_size = bits&#91;8&#58;12&#93;
        self.data_off = bits&#91;12&#58;16&#93;

    def __len__&#40;self&#41;&#58;
        return self.size
        
psf = None

def main&#40;argc, argv&#41;&#58;
    global psf

    PsfFilename = &#40; argv&#91;1&#58;2&#93;, PsfDefaultFile &#41;&#91;argc !=2&#93;   # I use a slice &#91;1&#58;2&#93; to avoid IndexError

    try&#58;
        PsfFile = open&#40;PsfFilename,'rb'&#41;
    except IOError, name&#58;
            print "File cannot be opened.", name
            sys.exit&#40;1&#41;

    psf = PsfFile.read&#40;&#41;
    PsfFile.close&#40;&#41;

    if not psf.find&#40;PsfMagic&#41; == 0&#58;
        print "This file is not a PSF file ! &#91;PSF Magic == 0x%08X&#93;\n" % str2hex&#40;PsfMagic&#41;
        sys.exit&#40;1&#41;

    psfheader = PsfHdr&#40;psf&#41;
    psfsections = PsfSec&#40;psf&#91;PsfHdr.size&#58;&#93;&#41;
    psflabels = psf&#91;le32&#40;psfheader.label_ptr&#41;&#58;&#93;
    psfdata = psf&#91;le32&#40;psfheader.data_ptr&#41;&#58;&#93;

    print "=============================================================================" 
    print "PlayStation Portable PSF File Data"
    print "=============================================================================" 
    print "\nFilename                &#58; %s\n" % PsfFilename 
    print "Start of section labels &#58; %2x" % le32&#40;psfheader.label_ptr&#41; 
    print "Start of section data   &#58; %2x" % le32&#40;psfheader.data_ptr&#41; 
    print "Unknown header data     &#58; %02x %02x %02x %02x" % &#40;
            psfheader.rfu000&#91;0&#93;,psfheader.rfu000&#91;1&#93;,psfheader.rfu000&#91;2&#93;,
            psfheader.rfu000&#91;3&#93;&#41;
    print "Number of Sections      &#58; %d\n" % le32&#40;psfheader.nsects&#41;
    print "Sect Loff Doff Dsiz Duse Dtyp Unkn     Label             Value"
    print "============================================================================="

    index = PsfHdr.size
    sect = psfsections
    
    for i in xrange&#40;0, le32&#40;psfheader.nsects&#41; &#41;&#58;
        print " %2d  %04x %04x %04x %04x  %02x  %04x     %-18s = " % &#40; i,
            le16&#40;sect.label_off&#41;, le32&#40;sect.data_off&#41;, le32&#40;sect.datafield_size&#41;,
            le32&#40;sect.datafield_used&#41;, sect.data_type, str2hex&#40;sect.rfu001&#41;,
            psflabels&#91;le16&#40;sect.label_off&#41;&#58;&#93;.split&#40;'\x00'&#41;&#91;0&#93; &#41;,

        if sect.data_type   == 0x2&#58;         # string
            print "%s" % psfdata&#91;le32&#40;sect.data_off&#41;&#58;&#93;.split&#40;'\x00\x00'&#41;&#91;0&#93;
            
        elif sect.data_type == 0x4&#58;         # Integer
            print "%d" % le32&#40;psfdata&#91;le32&#40;sect.data_off&#41;&#93;&#41;
                   
        elif sect.data_type == 0x0&#58;         # binary data ?
            print "Binary Data"
            
        else&#58;                               # Dunno yet
            print "Yet unknown. Please email save to wildwabbit@gmail"

        index += PsfSec.size
        sect = PsfSec&#40;psf&#91;index&#58;&#93;&#41;


    print "=============================================================================\n"
    print "Loff = Offset of the Label Field within the Label section."
    print "Doff = Offset of the Data Field within the Data section."
    print "Dsiz = Size of the Data Field within the Data section."
    print "Duse = Amount of the Data Field that currently contains data."
    print "Dtyp = The Data Field type. 0 = Binary &#40;?&#41;, 4 = Integer Word, 2 = String."
    print "Unkn = Unknown field usage.\n"

    return True

#Example Python Code&#58; END--------------------------------------------------------

if __name__ == '__main__'&#58;
    import sys
    main&#40;len&#40;sys.argv&#41;,sys.argv&#41;
-lan
PSP250
Posts: 12
Joined: Sat Nov 19, 2005 2:41 am

Post by PSP250 »

Good Job.

From my memdumps I could note these stubs are used for retrieving the information:

sceSystemFileGetIndexInfo
sceSystemFileGetIndex
sceSystemFileLoadIndex
sceSystemFileLoadAll2

Anyone actually succeeded in doing this on the PSP itself?
Post Reply