SceUtilitySavedataParam

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

Moderators: cheriff, TyRaNiD

Post Reply
kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

SceUtilitySavedataParam

Post by kgsws »

I dont know if it is somewhere on net ...
I wanted to update all 3 ports (hexen, heretic, doom) with PSP's system functions, and i discovered bug in SceUtilitySavedataParam, i found correct things in memory of original game, there is fix:

Code: Select all

typedef struct SceUtilitySavedataParam
{
	pspUtilityDialogCommon base;

	/** mode: 0 to load, 4 to load menu, 1 to save, 5 to save menu*/
       // Save/Load menu is that, you can choose from list of saves to save/load
	int mode;
	int unknown12;

	/** unknown13 use 1 */
	int unknown13;

	/** gameName: name used from the game for saves, equal for all saves */
	char gameName[16];
	/** saveName: name of the particular save, normally a number */
	char saveName[20]; // THIS IS FIX - only 20
	char *saveNames; // THIS IS NEW - For save/load menu (see example)
	/** fileName: name of the data file of the game for example DATA.BIN */
	char fileName[16];

	/** pointer to a buffer that will contain data file unencrypted data */
	void *dataBuf;
	/** size of allocated space to dataBuf */
	SceSize dataBufSize;
	SceSize dataSize;

	PspUtilitySavedataSFOParam sfoParam;

	PspUtilitySavedataFileData icon0FileData;
	PspUtilitySavedataFileData icon1FileData;
	PspUtilitySavedataFileData pic1FileData;
	PspUtilitySavedataFileData snd0FileData;

	unsigned char unknown17[4];
} SceUtilitySavedataParam;
how it works?
dont set saveName[20], but set savenames:

Code: Select all

typedef struct // you can use more names, but terminator must exist, and must be full of 0
{
	char name1[20];
	char name2[20];
	char name3[20];
	char name4[20];
	char name5[20];
	char nothing[20]; // Terminator
} savenames_t;

in code:
	savenames_t savenames;
	memset(&savenames, 0, sizeof(savenames));
	sprintf(savenames.name1,"s1");
	sprintf(savenames.name2,"s2");
	sprintf(savenames.name3,"s3");
	sprintf(savenames.name4,"s4");
	sprintf(savenames.name5,"s5");
	SceUtilitySavedataParam data;
	memset(&data, 0, sizeof(data));
	data.base.size = sizeof(data);
	data.base.language = PSP_SYSTEMPARAM_LANGUAGE_ENGLISH;
	data.base.buttonSwap = PSP_UTILITY_ACCEPT_CROSS;
	data.base.graphicsThread = 17;
	data.base.unknown = 19;
	data.base.fontThread = 18;
	data.base.soundThread = 16;
	data.mode = 5; // now saving menu
	data.unknown13 = 1;
	sprintf(data.gameName,"SOME-NAME");
	data.saveNames = &savenames; // <------- this is new
	sprintf&#40;data.fileName,"DATA.BIN"&#41;;
	data.dataBuf = savebuffer;
	data.dataBufSize = sizeof&#40;savebuffer&#41;;
	data.dataSize = sizeof&#40;savebuffer&#41;;
	sprintf&#40;data.sfoParam.title,"Game Title"&#41;;
	sprintf&#40;data.sfoParam.savedataTitle,"Save Title"&#41;;
	sprintf&#40;data.sfoParam.detail,"Save details"&#41;;
other is same as in SDK example
Last edited by kgsws on Thu Dec 06, 2007 3:44 am, edited 1 time in total.
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

Here's the modified psputility_savedata.h that i use if you want :

Code: Select all


/*
 * PSP Software Development Kit - http&#58;//www.pspdev.org
 * -----------------------------------------------------------------------
 * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
 *
 *  psputility_savedata.h - Definitions and Functions for savedata part of
 *                     pspUtility library
 *
 * Copyright &#40;c&#41; 2005    Shine
 *                       weltall <[email protected]>
 *                       Marcus R. Brown <[email protected]>
 *
 * $Id&#58; psputility_savedata.h 2275 2007-07-28 22&#58;02&#58;11Z iwn $
 */

#ifndef __PSPUTILITY_SAVEDATA_H__
#define __PSPUTILITY_SAVEDATA_H__

#include <psptypes.h>

#ifdef __cplusplus
extern "C" &#123;
#endif


#define PSP_UTILITY_SAVEDATA_LOADNOGRAPHIC		0
#define PSP_UTILITY_SAVEDATA_SAVENOGRAPHIC		1
#define PSP_UTILITY_SAVEDATA_LOAD				2
#define PSP_UTILITY_SAVEDATA_SAVE				3
#define PSP_UTILITY_SAVEDATA_LOADMULTIPLE		4
#define PSP_UTILITY_SAVEDATA_SAVEMULTIPLE		5


/** title, savedataTitle, detail&#58; parts of the unencrypted SFO
    data, it contains what the VSH and standard load screen shows */
typedef struct PspUtilitySavedataSFOParam
&#123;
	char title&#91;0x80&#93;;
	char savedataTitle&#91;0x80&#93;;
	char detail&#91;0x400&#93;;
	unsigned char parentalLevel;
	unsigned char unknown&#91;3&#93;;
&#125; PspUtilitySavedataSFOParam;

typedef struct PspUtilitySavedataFileData &#123;
	void *buf;
	SceSize bufSize;
	SceSize size;	/* ??? - why are there two sizes? */
	int unknown;
&#125; PspUtilitySavedataFileData;

typedef struct PspUtilitySavedataInfoShow
&#123;
	PspUtilitySavedataFileData icon;
	char *title;
&#125; PspUtilitySavedataInfoShow;


/** Structure to hold the parameters for the &#58;&#58;sceUtilitySavedataInitStart function.
  */
typedef struct SceUtilitySavedataParam
&#123;
	pspUtilityDialogCommon base;

	/** mode&#58; 0 to load, 1 to save */
	int mode;
	int unknown12;

	/** unknown13 use 0x1 */
	int unknown13;

	/** gameName&#58; name used from the game for saves, equal for all saves */
	char gameName&#91;16&#93;;
	/** saveName&#58; name of the particular save, normally a number */
	char saveName&#91;20&#93;;

	/** saveNameMultiple&#58; used by multiple modes */
	char **saveNameMultiple;

	/** fileName&#58; name of the data file of the game for example DATA.BIN */
	char fileName&#91;16&#93;;

	/** pointer to a buffer that will contain data file unencrypted data */
	void *dataBuf;
	/** size of allocated space to dataBuf */
	SceSize dataBufSize;
	SceSize dataSize;

	PspUtilitySavedataSFOParam sfoParam;

	PspUtilitySavedataFileData icon0FileData;
	PspUtilitySavedataFileData icon1FileData;
	PspUtilitySavedataFileData pic1FileData;
	PspUtilitySavedataFileData snd0FileData;

	PspUtilitySavedataInfoShow *infoShow;

	/* unknown1&#58; ? */
	int unknown1;

	/* unknown2&#58; ? */
	int unknown2&#91;4&#93;;

#ifdef PSP_UTILITY_SAVEDATAWITHKEY

	/* key&#58; encrypt/decrypt key for save with firmware >= 2.00 */
	char key&#91;16&#93;;

	/* unknown3&#58; ? */
	char unknown3&#91;20&#93;;

#endif

&#125; SceUtilitySavedataParam;


/**
 * Saves or Load savedata to/from the passed structure
 * After having called this continue calling sceUtilitySavedataGetStatus to
 * check if the operation is completed
 *
 * @param params - savedata parameters
 * @returns 0 on success
 */
int sceUtilitySavedataInitStart&#40;SceUtilitySavedataParam * params&#41;;

/**
 * Check the current status of the saving/loading/shutdown process
 * Continue calling this to check current status of the process
 * before calling this call also sceUtilitySavedataUpdate
 * @returns 2 if the process is still being processed.
 * 3 on save/load success, then you can call sceUtilitySavedataShutdownStart.
 * 4 on complete shutdown.
 */
int sceUtilitySavedataGetStatus&#40;void&#41;;


/**
 * Shutdown the savedata utility. after calling this continue calling
 * &#58;&#58;sceUtilitySavedataGetStatus to check when it has shutdown
 *
 * @return 0 on success
 *
 */
int sceUtilitySavedataShutdownStart&#40;void&#41;;

/**
 * Refresh status of the savedata function
 *
 * @param unknown - unknown, pass 1
 */
void sceUtilitySavedataUpdate&#40;int unknown&#41;;

#ifdef __cplusplus
&#125;
#endif

#endif

And to use it, it's like you do :

Code: Select all


PspUtilitySavedataInfoShow infoShow;
char *titleShow = "New data";
char nameMultiple&#91;&#93;&#91;20&#93; =
&#123;
 "0000",
 "0001",
 "0002",
 "0003",
 "0004",
 ""               // END OF LIST
&#125;;

char key&#91;&#93; = "SAMPLEKEYFOR2xxF";

void initSavedata&#40;SceUtilitySavedataParam * savedata, int mode&#41;
&#123;
SceUID fd;
int fsize;

	memset&#40;savedata, 0, sizeof&#40;SceUtilitySavedataParam&#41;&#41;;
	savedata->base.size = sizeof&#40;SceUtilitySavedataParam&#41;;

	savedata->base.language = 2;
	savedata->base.buttonSwap = 1;
	savedata->base.graphicsThread = 0x11;
	savedata->base.unknown = 0x13;
	savedata->base.fontThread = 0x12;
	savedata->base.soundThread = 0x10;

	savedata->mode = PSP_UTILITY_SAVEDATA_SAVEMULTIPLE;		/* mode&#58; 0 = load, 1 = save */
	savedata->unknown13 = 1; //?

//	strncpy&#40;savedata->key,key,16&#41;;

	strcpy&#40;savedata->gameName, "DEMO11111"&#41;;	/* first part of the save name, game identifier name */
	strcpy&#40;savedata->saveName, "0000"&#41;;	/* second part of the save name, save identifier name */


	savedata->saveNameMultiple = &#40;char **&#41; nameMultiple;

	strcpy&#40;savedata->fileName, "DATA.BIN"&#41;;	/* name of the data file */

	/* Allocate buffers used to store various parts of the save data. */
	savedata->dataBuf = malloc&#40;DATABUFFLEN&#41;;
	savedata->dataBufSize = DATABUFFLEN;
	savedata->dataSize = DATABUFFLEN;

	strcpy&#40;savedata->sfoParam.title,"Title"&#41;;
	strcpy&#40;savedata->sfoParam.savedataTitle,"Title 2"&#41;;
	strcpy&#40;savedata->sfoParam.detail,"Detail"&#41;;
	savedata->sfoParam.parentalLevel = 1;

	infoShow.title = titleShow;

	savedata->infoShow = &infoShow;
	//savedata->unknown = 1;
&#125;

kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

Post by kgsws »

i am not sure about this line:
char **saveNameMultiple;
it is pointer to pointer to char(s), but what i use is just:
char *saveNameMultiple;
pointer to char(s)
and with this:
savedata->saveNameMultiple = (char **) nameMultiple;
isnt better to do
savedata->saveNameMultiple = &nameMultiple;
of course if you use only one pointer (not pointer to pointer)
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

kgsws wrote:i am not sure about this line:
char **saveNameMultiple;
it is pointer to pointer to char(s), but what i use is just:
char *saveNameMultiple;
pointer to char(s)
and with this:
savedata->saveNameMultiple = (char **) nameMultiple;
isnt better to do
savedata->saveNameMultiple = &nameMultiple;
of course if you use only one pointer (not pointer to pointer)
I edited my post to cancel my bad reading.

You must use

savedata->saveNameMultiple = nameMultiple;

and not

savedata->saveNameMultiple = &nameMultiple;

simply because utility function takes a pointer to chars, if i use (char **), it's just for a more comprehensive reading.
Last edited by johnmph on Sat Dec 08, 2007 5:16 am, edited 3 times in total.
kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

Post by kgsws »

but, in first post is this:
in struct SceUtilitySavedataParam:

char *saveNames;
pointer to char(s), is it right?

and after i defined new struct
typedef struct
{
char name1[20];
char name2[20];
char name3[20];
char name4[20];
char name5[20];
char nothing[20]; // Terminator
} savenames_t;
no pointers, is it right?
after i create:
savenames_t savenames;
and this is not pointer too, is it right?

and on this line:
data.saveNames = &savenames;
i am making pointer to chars from char[120], is it right?

that means, you dont need to define:
savenames_t savenames;
but only:
char savenames[120];
but you must fill it in correct order
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

kgsws wrote:but, in first post is this:
in struct SceUtilitySavedataParam:

char *saveNames;
pointer to char(s), is it right?

and after i defined new struct
typedef struct
{
char name1[20];
char name2[20];
char name3[20];
char name4[20];
char name5[20];
char nothing[20]; // Terminator
} savenames_t;
no pointers, is it right?
after i create:
savenames_t savenames;
and this is not pointer too, is it right?

and on this line:
data.saveNames = &savenames;
i am making pointer to chars from char[120], is it right?

that means, you dont need to define:
savenames_t savenames;
but only:
char savenames[120];
but you must fill it in correct order
Yes i misread your first post, i don't know why i thought you used an array to chars ([][]), i am confused with my sample.
The sceUtilitySavedataInitStart takes a pointer to chars and he reads chars by 20, if he finds a empty string, he stops.

So you can use a string with 20, 40, 60, ... chars and use it like you said :

strcpy(&string[0],"0001");
strcpy(&string[20],"0002");
...
string[...] = 0; // terminator

with : savedata->saveNameMultiple = string;

if you use your structure declaration (char *saveNames;) or :

savedata->saveNameMultiple = (char **) string;

if you use my structure declaration (char **saveNameMultiple;)

But don't use : savedata->saveNameMultiple = &string;
kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

Post by kgsws »

but if i define pointer to something, an non pointer, then i must use & character ...

char *point; // 4 bytes
char nonpoint // 1 byte

i can do:
nonpoint = 'X';
but i cant do:
point = 'X'; // becouse pointer is not set, and it will try to write to address 0x00000000
i can use:
point = malloc(1);
and after it, i can use that ...
if i do:
point = &nonpoint;
it will set address of point to address of nonpoint, so when i try:
nonpoint = 'A';
point = 'X'; // or point[0] = 'X';
nonpoint will be 'X' there ...

that is way i am thinking about pointers :P

i am not sure with:
x = (char **)y; // conversion
so, i dont use it, if i dont need
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

kgsws wrote:but if i define pointer to something, an non pointer, then i must use & character ...

char *point; // 4 bytes
char nonpoint // 1 byte

i can do:
nonpoint = 'X';
but i cant do:
point = 'X'; // becouse pointer is not set, and it will try to write to address 0x00000000
i can use:
point = malloc(1);
and after it, i can use that ...
if i do:
point = &nonpoint;
it will set address of point to address of nonpoint, so when i try:
nonpoint = 'A';
point = 'X'; // or point[0] = 'X';
nonpoint will be 'X' there ...

that is way i am thinking about pointers :P

i am not sure with:
x = (char **)y; // conversion
so, i dont use it, if i dont need
You are right except a little mistake :

point = 'X'; // or point[0] = 'X'; is not the same !!!

point is the pointer, it contains address of pointed data and not data, here's the good writing (parentheses is not necessary in this sample) :

(*point) = 'X'; // or point[0] = 'X';

For this line :

x = (char **)y; // conversion

It's just a cast, if you do :

char **point = (char **) &nonpoint;
*((char *) point) = 'X';

it's the same that :

char *point = &nonpoint;
*point = 'X';

But it's off topic.

The reason why i use char **saveNameMultiple with an array of strings instead char *saveNameMultiple with a large string is because it's more easy i think.
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

and you can found many tutorials on pointers on internet
kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

Post by kgsws »

great, now i understant it more, but if i create:

Code: Select all

char *names&#91;6&#93; = &#123;
	"NAME1",
	"NAME2",
	"NAME3",
	"NAME4",
	"NAME5",
	"" // Terminator
&#125;;
then its size is 6*4 bytes, and every 4 bytes is pointer to char(s).
For every NAME, you must alloc memory (or use it like that example, it is defined in program)

But what i saw in memory of official game was this:
char nameschars[6*20]; // 5 savenames, every 20 chars long, and 20 chars terminator.
Of course, size is 6*20

If you point to 'names' then it is pointer to pointers to chars (and that was not in memory.

I dont know if savegame can work with pointer to pointers or only with pointer to chars, but i can try it (now i am using just pointer to chars, same as in original game)

(from your example):

Code: Select all

char nameMultiple&#91;&#93;&#91;20&#93; =
&#123;
 "0000",
 "0001",
 "0002",
 "0003",
 "0004",
 ""               // END OF LIST
&#125;; 
there isnt any pointer, right?
it is like char nameMultiple[6*20], and if i use "0000" as first name, it will be saved to nameMultiple[0], and "0001" to nameMultiple[20], right?

And you can make pointer from it by point = &nameMultiple like i.
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

Yes you are right and it's because i use :

savedata->saveNameMultiple = (char **) nameMultiple;

instead :

savedata->saveNameMultiple = (char **) &nameMultiple;

The savegame function takes a pointer to char and not a pointer to pointer to chars and it's why i use a large string (char nameMultiple[][20]) but when i reversed this function, i wrote it as char** instead char* because i think that it's more representive for the meaning of how it's used.

But you can also write it like (in structure) :

int nameMultiple;

and after use it like :

char name[120] = "...";
struct.nameMultiple = (int) name;

It's valid too but it's not very good to understand lol

So the savedata function takes a pointer to chars and reads the chars by 20 until he finds 0 as first char (terminator).
kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

Post by kgsws »

i still dont understand why:
savedata->saveNameMultiple = (char **) nameMultiple;
and no:
savedata->saveNameMultiple = &nameMultiple;
(it is just pointer = pointer) (becouse & makes pointer from non pointer)

becouse there are two '**' markers, every marker means pointer, so it is pointer to pointer to ...

if i do:
char **something;
then it is pointer to pointer to char(s), so:
something = malloc(x * 4) // x = num pointers, 4 is size of pointer
and then i can do:
something[0] = malloc(10); // 10 chars
something[1] = malloc(20); // 20 chars
.....
and then:
printf(something[0]); // 10 chars
printf(something[1]); // 20 chars
.....

it is strange, becouse of compiler ...
sprintf accepts pointer to char (so char*)
but when i do:
char some[20];
and then:
printf(some); it automaticaly converts non pointer to pointer
(becouse if not, it will try to use first 4 chars as address of pointer, and that is bad)
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

Because an array = a pointer :

char some[20];

some is a pointer to 20 bytes data allocated statically.

char *some2 = some;

some2 is a pointer which points to the same memory, it's the same !
kgsws
Posts: 7
Joined: Thu Dec 06, 2007 12:44 am

Post by kgsws »

yes, but compiler can handle it diffrend way than creating a pointer by using *.

if you thing that way, then everything is pointer to some location in memory (yes, data must be stored somewhere)

int is array of 4 chars:
int somenum;
char somechars[4];

char is pointer without using *?
and why int isnt?

but compiler can make pointer from somechars automaticaly by using it as x = somechars; but if i use x = &somechars; it does not create pointer to pointer, then savedata

Size is same, i thing, everything hadles compiler, like MSVC .NET, it does not allow some things, what DEV C++ does. (yes i had some problems with it)

isnt '(char*)' just fake conversion, for using variable as diffrend type?

tested:
char text[] = "test text";
printf("0x%08X\n",text);
printf("0x%08X\n",&text);
both lines shown same hex number, so it does not depends on '&'
then i dont need to use it, but 'char *saveNames;' is right (only one pointer)
User avatar
Jim
Posts: 476
Joined: Sat Jul 02, 2005 10:06 pm
Location: Sydney
Contact:

Post by Jim »

Right, because if you have

char x[]="foo";
Then

x is type pointer to char
&x is type pointer to array of char

They're both point to the same address, but they have different types.

I don't know what you're all on about, this is utterly basic C programming.

Jim
Post Reply