Skip to content

Commit

Permalink
Add bare-bones playgo chunk support
Browse files Browse the repository at this point in the history
  • Loading branch information
maxton committed Dec 24, 2018
1 parent d12d697 commit 63fefea
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 18 deletions.
4 changes: 2 additions & 2 deletions LibOrbisPkg/GP4/Gp4Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public void SetType(VolumeType type)
type = "sp",
initial_chunk_count = 1,
label = "Scenario #0",
number = 0,
chunks = "0",
}
}
},
Expand Down Expand Up @@ -388,7 +388,7 @@ public class Scenario
[XmlAttribute(AttributeName = "label")]
public string label;
[XmlText]
public int number;
public string chunks;
}
public class ScenarioInfo
{
Expand Down
2 changes: 2 additions & 0 deletions LibOrbisPkg/LibOrbisPkg.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
<Compile Include="PKG\Pkg.cs" />
<Compile Include="PKG\PkgReader.cs" />
<Compile Include="PKG\PkgWriter.cs" />
<Compile Include="PlayGo\ChunkDat.cs" />
<Compile Include="PlayGo\Manifest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rif\LicenseDat.cs" />
<Compile Include="Rif\LicenseInfo.cs" />
Expand Down
2 changes: 1 addition & 1 deletion LibOrbisPkg/PKG/Entry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public GenericEntry(EntryId id, string name = null)
public byte[] FileData;
public override EntryId Id { get; }
public override string Name { get; }
public override uint Length => (uint)FileData.Length;
public override uint Length => (uint)(FileData?.Length ?? 0);
public override void Write(Stream s)
{
s.Write(FileData, 0, FileData.Length);
Expand Down
3 changes: 3 additions & 0 deletions LibOrbisPkg/PKG/Pkg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public class Pkg
public GenericEntry LicenseInfo;
public SfoEntry ParamSfo;
public GenericEntry PsReservedDat;
public PlayGo.ChunkDat ChunkDat;
public GenericEntry ChunkSha;
public GenericEntry ChunkXml;

public List<Entry> Entries;

Expand Down
74 changes: 62 additions & 12 deletions LibOrbisPkg/PKG/PkgBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ public PkgBuilder(GP4.Gp4Project proj, string proj_dir)
/// <returns>Completed Pkg structure</returns>
public Pkg Write(Stream s)
{
var pkg = BuildPkg();
var writer = new PkgWriter(s);

// Write PFS first, to get stream length
s.Position = (long) pkg.Header.pfs_image_offset;
var EKPFS = Crypto.ComputeKeys(project.volume.Package.ContentId, project.volume.Package.Passcode, 1);
var pfsStream = new OffsetStream(s, s.Position);
Console.WriteLine("Preparing inner PFS...");
var innerPfs = new PFS.PfsBuilder(PFS.PfsProperties.MakeInnerPFSProps(project, projectDir), x => Console.WriteLine($"[innerpfs] {x}"));
Console.WriteLine("Preparing outer PFS...");
var outerPfs = new PFS.PfsBuilder(PFS.PfsProperties.MakeOuterPFSProps(project, innerPfs, EKPFS), x => Console.WriteLine($"[outerpfs] {x}"));

var pkg = BuildPkg(outerPfs.CalculatePfsSize());
var writer = new PkgWriter(s);
s.Position = (long)pkg.Header.pfs_image_offset;
var pfsStream = new OffsetStream(s, s.Position);
outerPfs.WriteImage(pfsStream);

// Update header sizes now that we know how big things are...
Expand All @@ -60,6 +60,12 @@ public Pkg Write(Stream s)
}
CalcGeneralDigests(pkg);
pkg.ImageKey.FileData = Crypto.RSA2048EncryptKey(RSAKeyset.FakeKeyset.Modulus, EKPFS);
if(pkg.Header.content_type == ContentType.GD)
{
CalcPlaygoDigests(pkg, s);
pkg.ChunkDat.MchunkAttrs[0].size = (ulong)s.Length;
pkg.ChunkDat.InnerMChunkAttrs[0].size = (ulong)innerPfs.CalculatePfsSize();
}

// Write body now because it will make calculating hashes easier.
writer.WriteBody(pkg, project.volume.Package.ContentId, project.volume.Package.Passcode);
Expand Down Expand Up @@ -175,10 +181,19 @@ private static void CalcBodyDigests(Pkg pkg, Stream s)
}
}

private static void CalcPlaygoDigests(Pkg pkg, Stream s)
{
const int CHUNK_SIZE = 0x10000;
for(long i = (long)pkg.Header.pfs_image_offset / CHUNK_SIZE; i < s.Length / CHUNK_SIZE; i++)
{
Buffer.BlockCopy(Crypto.Sha256(s, i * CHUNK_SIZE, CHUNK_SIZE), 0, pkg.ChunkSha.FileData, (int)i * 4, 4);
}
}

/// <summary>
/// Create the Pkg struct. Does not compute hashes or data sizes.
/// </summary>
public Pkg BuildPkg()
public Pkg BuildPkg(long pfsSize)
{
var pkg = new Pkg();
var volType = project.volume.Type;
Expand Down Expand Up @@ -217,7 +232,7 @@ public Pkg BuildPkg()
pfs_image_count = 1,
pfs_flags = 0x80000000000003CC,
pfs_image_offset = 0x80000,
pfs_image_size = 0,
pfs_image_size = (ulong)pfsSize,
mount_image_offset = 0,
mount_image_size = 0,
package_size = 0,
Expand Down Expand Up @@ -278,12 +293,31 @@ public Pkg BuildPkg()
pkg.GeneralDigests,
pkg.Metas,
pkg.Digests,
pkg.EntryNames,
pkg.EntryNames
};
if (pkg.Header.content_type == ContentType.GD)
{
pkg.ChunkDat = PlayGo.ChunkDat.FromProject(project);
pkg.ChunkSha = new GenericEntry(EntryId.PLAYGO_CHUNK_SHA, "playgo-chunk.sha");
pkg.ChunkXml = new GenericEntry(EntryId.PLAYGO_MANIFEST_XML, "playgo-manifest.xml")
{
FileData = PlayGo.Manifest.Default
};
// Add playgo entries for GD PKGs
pkg.Entries.AddRange(new Entry[]
{
pkg.ChunkDat,
pkg.ChunkSha,
pkg.ChunkXml
});
}
pkg.Entries.AddRange(new Entry[]
{
pkg.LicenseDat,
pkg.LicenseInfo,
pkg.ParamSfo,
pkg.PsReservedDat
};
});
foreach(var file in project.files.Items.Where(f => f.DirName == "sce_sys/"))
{
var name = file.FileName;
Expand All @@ -294,10 +328,26 @@ public Pkg BuildPkg()
pkg.Digests.FileData = new byte[pkg.Entries.Count * Pkg.HASH_SIZE];

// 1st pass: set names
foreach (var entry in pkg.Entries)
foreach (var entry in pkg.Entries.OrderBy(e => e.Name))
{
pkg.EntryNames.GetOffset(entry.Name);
}
// estimate size for playgo
if (pkg.Header.content_type == ContentType.GD)
{
long bodySize = 0;
foreach(var e in pkg.Entries)
{
bodySize += (e.Length + 15) & ~15; // round up to nearest 16
}
bodySize += 32 * pkg.Entries.Count; // metas
bodySize += 4 * (pfsSize / 0x10000); // playgo hashes of pfs
if (bodySize + (long)pkg.Header.body_offset >= (long)pkg.Header.pfs_image_offset)
{
pkg.Header.pfs_image_offset += 0x10000;
}
pkg.ChunkSha.FileData = new byte[4 * ((pkg.Header.pfs_image_offset + pkg.Header.pfs_image_size) / 0x10000)];
}
// 2nd pass: set sizes, offsets in meta table
var dataOffset = 0x2000u;
var flagMap = new Dictionary<EntryId,uint>() {
Expand Down Expand Up @@ -353,7 +403,7 @@ private byte[] GenLicense(Pkg pkg)
var license = new LicenseDat(
pkg.Header.content_id,
pkg.Header.content_type,
project.volume.Package.EntitlementKey.FromHexCompact());
project.volume.Package.EntitlementKey?.FromHexCompact());
using (var ms = new MemoryStream())
{
new LicenseDatWriter(ms).Write(license);
Expand All @@ -367,7 +417,7 @@ private byte[] GenLicenseInfo(Pkg pkg)
var info = new LicenseInfo(
pkg.Header.content_id,
pkg.Header.content_type,
project.volume.Package.EntitlementKey.FromHexCompact());
project.volume.Package.EntitlementKey?.FromHexCompact());
using (var ms = new MemoryStream())
{
new LicenseInfoWriter(ms).Write(info);
Expand Down
Loading

0 comments on commit 63fefea

Please sign in to comment.