Update 1: New image more detailed, text clean up
Update 2: Added "speciall variables with unknown content" and some info about gamesaves
Intro
I will try to explain how to build an .sfo from scratch with only a hex editor and a calculator
This give you the flexibility to manipulate them more deeper than any of the actual existant apps (i.e. actually there is no way to "inject" a new variable to an existant .sfo)... additionally, SFO editor for windows has several bugs that ruins the file (it breaks ATRIBUTE, and it lets you add padding)
The picture is a PARAM.SFO from the unnofficial SDK fleshl1ght, where i removed completly the variables LICENSE & PARENTAL_LEVEL (because i think are just restrictions for the user and not usefull, and let me create a minimall file for the example)
My intention is to document this to ps3devwiki, but im more used to forums, so i will use this message to put some order in my notes
PARAM.SFO layout

The structure can be divided in 4 areas:
1,2,3,4,5 is the header
6,7,8,9,10 is the variable table
11 is name table
12 is data table
Colours
Yellow areas (3,6,11) refers to names (position, offset, and table)
Blue areas (4,10,12) refers to datas (position, offset, and table)
Light-blue areas (8,9) refers to data sizes (bytes used, block size)
Padding & Sizes
DONT ADD PADDING, the padding is fixed for every value and is very restrictive, the only place where there is padding is at the end of the "name table", is needed to adjust the size of the whole table to the next multiply of 4 (bytes)
The values at the data table can be of 2 types (defined by "data type") UTF-8... or int32
UTF-8 values must be added +1 byte of separation (this includes all the names at the "name table")
int32 values has a fixed "block size" that depends of the variable. I.E. TITLE is 128 bytes long, while BOOTABLE is 4 bytes long
DONT CHANGE THE BLOCK SIZES, because the ps3 is waiting for a fixed block size (defined in other parts of the firmware), if you use a not-standard "block size" the rest of the .sfo will be readed like corrupted
Note that areas 8 & 9 (data used size, and data block size) are very dependant
By a simply substraction (9-8) you know the padding (btw... like i said, padding has no importance, because is fixed, and CANT be modifyed in ANY way)... either way, padding can be used for verification purposes
When modifying the TITLE of a original PARAM.SFO (not created by you)... you need to change the "data used size" (8) of the value TITLE in his line of the variable table
I.E. a game whose name is: "HIPERAMAZING" (is using 12 bytes + 1 because is UTF-8) and you change it to: "Decent Name Game" (you are using 16 + 1 because is UTF-8)
Little endian & Big endian
The header, and the variable table are in "little endian", the way humans read numbers is exactly the opposite (big endian), so is needed to reverse the order of the value byte by byte to understand something, some examples:
Little endian --->reversed---> big endian
11 22 33 44 --->reversed---> 44 33 22 11 = 44332211
12 34 56 78 --->reversed---> 78 56 34 12 = 78563412
01 00 00 00 --->reversed---> 00 00 00 01 = 1
00 00 00 01 --->reversed---> 01 00 00 00 = 1000000
18 01 00 00 --->reversed---> 00 00 01 18 = 118 <----- this is the "data table start position" (4) used in the picture
Calculations
Code:
File type
--------
.PSF
File version
-----------
1.1
Start of "Variable_Name_Table"
------------------------------
B4 00 00 00 --->reversed---> 00 00 00 B4 = 0x00B4
Start of "Variable_Data_Table"
------------------------------
18 01 00 00 --->reversed---> 00 00 01 18 = 0x0118
Number of Variables
-------------------
0A 00 00 00 --->reversed---> 00 00 00 0A = A <---hex2dec---> = 10
-----------------------------------------------------------------------------------------------
=============FROM THIS POINT THIS STRUCTURE REPEATS FOR EVERY VARIABLE=========
-----------------------------------------------------------------------------------------------
Zero based offset of variable "Name" from Start of "Variable_Name_Table" (name offset)
--------------------------------------------------------------------------------------
APP_VER 0x00B4-0x00B4=00 = 00 00 00 00 --->reversed---> 00 00 00 00
ATTRIBUTE 0x00BC-0x00B4=08 = 00 00 00 08 --->reversed---> 08 00 00 00
BOOTABLE 0x00C6-0x00B4=12 = 00 00 00 12 --->reversed---> 12 00 00 00
CATEGORY 0x00CF-0x00B4=1B = 00 00 00 1B --->reversed---> 1B 00 00 00
PS3_SYSTEM_VER 0x00D8-0x00B4=24 = 00 00 00 24 --->reversed---> 24 00 00 00
RESOLUTION 0x00E7-0x00B4=33 = 00 00 00 33 --->reversed---> 33 00 00 00
SOUND_FORMAT 0x00F2-0x00B4=3E = 00 00 00 3E --->reversed---> 3E 00 00 00
TITLE 0x00FF-0x00B4=4B = 00 00 00 4B --->reversed---> 4B 00 00 00
TITLE_ID 0x0105-0x00B4=51 = 00 00 00 51 --->reversed---> 51 00 00 00
VERSION 0x010E-0x00B4=5A = 00 00 00 5A --->reversed---> 5A 00 00 00
data_type
---------
04 02 = UTF8
04 04 = int32
04 04 = int32
04 02 = UTF8
04 02 = UTF8
04 04 = int32
04 04 = int32
04 02 = UTF8
04 02 = UTF8
04 02 = UTF8
Total Used Bytes of variable "Data" in Current Data Block (data size)
-------------------------------------------------------------------------
Data type 2=UTF-8 variables must be added + 1
01.00 =5+1=6 bytes <---dec2hex---> 6 = 00 00 00 06 --->reversed---> 06 00 00 00
00 00 02 00 =4 bytes <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
01 00 00 00 =4 bytes <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
DG =2+1=3 bytes <---dec2hex---> 3 = 00 00 00 03 --->reversed---> 03 00 00 00
03.4100 =7+1=8 bytes <---dec2hex---> 8 = 00 00 00 08 --->reversed---> 08 00 00 00
3F 00 00 00 =4 bytes <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
17 03 00 00 =4 bytes <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
Disc Package Installer =22+1=23 bytes <---dec2hex---> 17 = 00 00 00 17 --->reversed---> 17 00 00 00
DPIX00001 =9+1=10 bytes <---dec2hex---> A = 00 00 00 0A --->reversed---> 0A 00 00 00
01.00 =5+1=6 bytes <---dec2hex---> 6 = 00 00 00 06 --->reversed---> 06 00 00 00
Total Size In Bytes of variable "Data" in Current Data Block (block size)
-----------------------------------------------------------------------------------------------
Data type 2=UTF-8 variables must be added + 1
Valid block sizes in decimal ---> 2^1=2 2^2=4 2^3=8 2^4=16 2^5=32 2^6=64 2^7=128 2^8=256 2^9=512 2^10=1024 etc...
v
01.00 =5+1=6 bytes + 2 padding = 8 <---dec2hex---> 8 = 00 00 00 08 --->reversed---> 08 00 00 00
00 00 02 00 =4 bytes + 0 padding = 4 <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
01 00 00 00 =4 bytes + 0 padding = 4 <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
DG =2+1=3 bytes + 1 padding = 4 <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
03.4100 =7+1=8 bytes + 0 padding = 8 <---dec2hex---> 8 = 00 00 00 08 --->reversed---> 08 00 00 00
3F 00 00 00 =4 bytes + 0 padding = 4 <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
17 03 00 00 =4 bytes + 0 padding = 4 <---dec2hex---> 4 = 00 00 00 04 --->reversed---> 04 00 00 00
Disc Package Installer =22+1=23 bytes + 105 padding = 128 <---dec2hex---> 80 = 00 00 00 80 --->reversed---> 80 00 00 00
DPIX00001 =9+1=10 bytes + 6 padding = 16 <---dec2hex---> 10 = 00 00 00 10 --->reversed---> 10 00 00 00
01.00 =5+1=6 bytes + 2 padding = 8 <---dec2hex---> 8 = 00 00 00 08 --->reversed---> 08 00 00 00
Zero based offset of variable "Data" from start of "Variable_Data_Table" (data offset)
--------------------------------------------------------------------------------------
01.00 0x0118-0x0118= 00 = 00 00 00 00 --->reversed---> 00 00 00 00
00 00 02 00 0x0120-0x0118= 08 = 00 00 00 08 --->reversed---> 08 00 00 00
01 00 00 00 0x0124-0x0118= 0C = 00 00 00 0C --->reversed---> 0C 00 00 00
DG 0x0128-0x0118= 10 = 00 00 00 10 --->reversed---> 10 00 00 00
03.4100 0x012C-0x0118= 14 = 00 00 00 14 --->reversed---> 14 00 00 00
3F 00 00 00 0x0134-0x0118= 1C = 00 00 00 1C --->reversed---> 1C 00 00 00
17 03 00 00 0x0138-0x0118= 20 = 00 00 00 20 --->reversed---> 20 00 00 00
Disc Package Installer 0x013C-0x0118= 24 = 00 00 00 24 --->reversed---> 24 00 00 00
DPIX00001 0x01BC-0x0118= A4 = 00 00 00 A4 --->reversed---> A4 00 00 00
01.00 0x01CC-0x0118= B4 = 00 00 00 B4 --->reversed---> B4 00 00 00
Tips & Rules
I used an "standard" .SFO for hombrew, apps, and disc games, but .SFO are used in many kinds of content as trophies, savegames, etc...
.SFO files are used as a preview of the folder, and to manage boot parameters of the content (like a program, a video, etc, etc...)
The name of the variables included in the "variable name table" can vary depending of where the .sfo is used, but there are allways in alphabetically order (ATTRIBUTE, BOOTABLE, C..., D..., E..., and so on)
The allowed variables for the PS3 firmware depends of where the .SFO is used (I.E.different entryes if the .SFO is from a savegame or from a blueray game)
Some ones are mandatory for a CATTEGORY (I.E. BOOTABLE is mandatory if you want a program to boot)
Others are optionall (like TITLE_02, TITLE03, TITLE04 for languages)
Some others are ignored when you use them in other CATTEGORY not desired by sony (im not sure what is limiting this from the firmware), but as an example... you CANT add a SUB_TITLE text line for a homebrew
For a non-complet-yet list of all variables look at this link --->
http://www.ps3devwiki.com/index.php?...Alphabetically
----------------------------------------------------------------------------------------------
When calculating the "data bytes used" is needed to add a +1 for every "UTF8" data type
"data_block_size" has a fixed size in bytes that depends of the variable refered (size is in a relation of 2^x in decimal)
i.e. LICENSE has a lenght og 128 bytes.... and BOOTABLE has a lenght of 4 bytes
DONT CHANGE THIS LENGHTS... DONT ADD RANDOM PADDING
If you need to know the padding (for some strange reason) you can by simply making a sustraction (block size in bytes - bytes used)
For the block sizes refer to the previous list --->
http://www.ps3devwiki.com/index.php?...Alphabetically
Int32 data type (in most cases) must be converted to binary, this is a way to understand the "flags" from a "human point of view"
The most interesting flags are managed by ATTRIBUTE, there some unknown ones, and (especulation) some ones reserved for future implementations from sony
For the (unfinished) list of ATTRIBUTE flags refer to this link --->
http://www.ps3devwiki.com/index.php?....SFO#ATTRIBUTE
There are (at least) 3 different kinds of data type, remeber that UTF8 values needs a +1 when calculating,
04 00 = blank
04 02 = UTF8
04 04 = int32
Speciall variables with unknown content
Code:
Savegames
------------
0x558 PARAMS (uint1024)
0x558 24 (8+4+4+4+4?) ?????????
0x570 (uint4) Console User Account nš
0x574 (uint16) Console ID
0x584 (uint4) Console User Account nš
0x588 (uint16) PSN User account ID
0x598 960 ? ?????????
0x958 PARAMS2 (uint12) 8+4 ?

This values are the known part of the variable
PARAMS from the screencapture
Unknown = 02040102 03000000 00000000 CF120000 00000000 05000000
Console User Account nš = 02 00 00 00 <---reversed---> 00 00 00 02 = 2
Console ID = EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
Console User Account nš = 02 00 00 00 <---reversed---> 00 00 00 02 = 2
PSN User account ID = CCCCCCCC CCCCCCCC CCCCCCCC CCCCCCCC
Rest bytes = unknown
|
The contents of the variable
PARAMS2 is unknown, but his size is 12 bytes (weird... because is the only one that doenst fit the relation 2^x for his block size)
-----\o/-----
I will keep editing this message with more tips, file examples, etc... enought by now

Feel free to ask whatever doubt and i will reply with more examples, or make suggestions, by now is a bit mess
The file used in the example picture is attached at the end of this message