Skip to content

Commit

Permalink
Add Param.SFO read/write, actually write pubtoolinfo into it
Browse files Browse the repository at this point in the history
  • Loading branch information
maxton committed Nov 10, 2018
1 parent 7bfc210 commit 6d1e3b4
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 8 deletions.
11 changes: 10 additions & 1 deletion LibOrbisPkg/PKG/PkgBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,19 @@ public Pkg BuildPkg()
pkg.LicenseInfo = new GenericEntry(EntryId.LICENSE_INFO) { FileData = new byte[512] };
var paramSfoPath = project.files.Where(f => f.TargetPath == "sce_sys/param.sfo").First().OrigPath;
using (var paramSfo = File.OpenRead(Path.Combine(projectDir, paramSfoPath)))
{
// TODO: What are these "size" values?
var sfo = SFO.ParamSfo.FromStream(paramSfo);
sfo.Values.Add(new SFO.Utf8Value(
"PUBTOOLINFO",
"c_date=20181107,img0_l0_size=20,img0_l1_size=0,img0_sc_ksize=512,img0_pc_ksize=576",
0x200));
sfo.Values.Add(new SFO.IntegerValue("PUBTOOLVER", 0x02890000));
pkg.ParamSfo = new GenericEntry(EntryId.PARAM_SFO, "param.sfo")
{
FileData = SFO.ParamSfo.Update(paramSfo)
FileData = sfo.Serialize()
};
}
pkg.PsReservedDat = new GenericEntry(EntryId.PSRESERVED_DAT) { FileData = new byte[0x2000] };
pkg.Entries = new List<Entry>
{
Expand Down
160 changes: 156 additions & 4 deletions LibOrbisPkg/SFO/ParamSfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,169 @@
using System.IO;
using System.Linq;
using System.Text;
using LibOrbisPkg.Util;

namespace LibOrbisPkg.SFO
{
public class ParamSfo
{
public static byte[] Update(Stream s)
public List<Value> Values;
public ParamSfo()
{
// TODO: Add pubtools info to SFO
var ret = new byte[s.Length + 572];
s.Read(ret, 0, (int)s.Length);
Values = new List<Value>();
}
public Value GetValueByName(string name)
{
foreach(var v in Values)
{
if (v.Name == name) return v;
}
return null;
}

public static ParamSfo FromStream(Stream s)
{
var ret = new ParamSfo();
s.Position = 8;
var keyTableStart = s.ReadInt32LE();
var dataTableStart = s.ReadInt32LE();
var numValues = s.ReadInt32LE();
for(int value = 0; value < numValues; value++)
{
s.Position = value * 0x10 + 0x14;
var keyOffset = s.ReadUInt16LE();
var format = (SfoEntryType)s.ReadUInt16LE();
var len = s.ReadInt32LE();
var maxLen = s.ReadInt32LE();
var dataOffset = s.ReadUInt32LE();
s.Position = keyTableStart + keyOffset;
var name = s.ReadASCIINullTerminated();
s.Position = dataTableStart + dataOffset;
switch(format)
{
case SfoEntryType.Integer:
ret.Values.Add(new IntegerValue(name, s.ReadInt32LE()));
break;
case SfoEntryType.Utf8:
ret.Values.Add(new Utf8Value(name, Encoding.UTF8.GetString(s.ReadBytes(len > 0 ? len - 1 : len)), maxLen));
break;
case SfoEntryType.Utf8Special:
ret.Values.Add(new IntegerValue(name, s.ReadInt32LE()));
break;
default:
throw new Exception($"Unknown SFO type: {(ushort)format:X4}");
}
}
return ret;
}

public void Write(Stream s)
{
int keyTableOffset = 0x14;
int keyTableSize = 0x0;
int dataSize = 0x0;
Values.Sort((v1, v2) => v1.Name.CompareTo(v2.Name));
foreach (var v in Values)
{
keyTableOffset += 0x10;
keyTableSize += v.Name.Length + 1;
dataSize += v.MaxLength;
}
int dataTableOffset = keyTableOffset + keyTableSize;
if (dataTableOffset % 4 != 0) dataTableOffset += 4 - (dataTableOffset % 4);
s.SetLength(0);
s.SetLength(dataTableOffset + dataSize);
s.WriteInt32BE(0x00505346); // " PSF" magic
s.WriteInt32LE(0x101); // Version?
s.WriteInt32LE(keyTableOffset);
s.WriteInt32LE(dataTableOffset);
s.WriteInt32LE(Values.Count);
int keyOffset = 0, dataOffset = 0, index = 0;
foreach (var v in Values)
{
s.Position = 0x14 + 0x10 * index++;
s.WriteUInt16LE((ushort)keyOffset);
s.WriteUInt16LE((ushort)v.Type);
s.WriteInt32LE(v.Length);
s.WriteInt32LE(v.MaxLength);
s.WriteInt32LE(dataOffset);
s.Position = keyTableOffset + keyOffset;
s.Write(Encoding.ASCII.GetBytes(v.Name), 0, v.Name.Length);
s.WriteByte(0);
s.Position = dataTableOffset + dataOffset;
var val = v.ToByteArray();
s.Write(val, 0, val.Length);
keyOffset += v.Name.Length + 1;
dataOffset += v.MaxLength;
}
}
public byte[] Serialize()
{
using (var s = new MemoryStream())
{
Write(s);
return s.ToArray();
}
}
}

public enum SfoEntryType : ushort
{
Utf8Special = 0x4,
Utf8 = 0x204,
Integer = 0x404
};
public abstract class Value
{
public Value(string name, SfoEntryType type)
{
Name = name; Type = type;
}
public SfoEntryType Type;
public string Name;
public abstract int Length { get; }
public abstract int MaxLength { get; }
public abstract byte[] ToByteArray();
}
public class Utf8SpecialValue : Value
{
public Utf8SpecialValue(string name, byte[] value, int maxLength)
: base(name, SfoEntryType.Utf8Special)
{
Type = SfoEntryType.Utf8Special;
MaxLength = maxLength;
Value = value;
}
public byte[] Value;
public override int Length => Value.Length;
public override int MaxLength { get; }
public override byte[] ToByteArray() => Value;
}
public class Utf8Value : Value
{
public Utf8Value(string name, string value, int maxLength)
: base(name, SfoEntryType.Utf8)
{
Type = SfoEntryType.Utf8;
MaxLength = maxLength;
Value = value;
}
public override int Length => Encoding.UTF8.GetByteCount(Value) + 1;
public override int MaxLength { get; }
public string Value;
public override byte[] ToByteArray() => Encoding.UTF8.GetBytes(Value);
}
public class IntegerValue : Value
{
public IntegerValue(string name, int value)
: base(name, SfoEntryType.Integer)
{
Type = SfoEntryType.Integer;
Value = value;
}
public override int Length => 4;
public override int MaxLength => 4;
public int Value;
public override byte[] ToByteArray() => BitConverter.GetBytes(Value);
}
}
6 changes: 3 additions & 3 deletions LibOrbisPkg/Util/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,10 @@ public static float ReadFloat(this Stream s)
public static string ReadASCIINullTerminated(this Stream s, int limit = -1)
{
StringBuilder sb = new StringBuilder(255);
char cur;
while ((limit == -1 || sb.Length < limit) && (cur = (char)s.ReadByte()) != 0)
int cur;
while ((limit == -1 || sb.Length < limit) && (cur = s.ReadByte()) > 0)
{
sb.Append(cur);
sb.Append((char)cur);
}
return sb.ToString();
}
Expand Down
19 changes: 19 additions & 0 deletions SFO.bt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
enum <uint16> param_fmt {
utf8_special = 0x4,
utf8 = 0x204,
integer = 0x404
};

char magic[4];
int version;
int key_table_start;
int data_table_start;
int num_entries;
struct {
uint16 keyOffset; //offset of keytable + keyOffset
param_fmt format; //enum (see below)
uint32 paramLen;
uint32 paramMaxLen;
uint32 dataOffset; //offset of datatable + dataOffset
} indices[num_entries];
FSeek(key_table_start);

0 comments on commit 6d1e3b4

Please sign in to comment.