Skip to content

Commit

Permalink
Various fixes, do not hardcode vol data size
Browse files Browse the repository at this point in the history
  • Loading branch information
Nenkai committed Jan 6, 2024
1 parent 9be1027 commit 99b0932
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 1,015 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "PDTools"]
path = PDTools
url = https://github.com/Nenkai/PDTools.git
14 changes: 7 additions & 7 deletions GTPSPVolTools.sln
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31515.178
# Visual Studio Version 17
VisualStudioVersion = 17.7.34221.43
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GTPSPVolTools", "GTPSPVolTools\GTPSPVolTools.csproj", "{635F7BAF-FCAE-4EB7-B2B1-ED8BC060D64C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PDTools.Utils", "PDTools.Utils\PDTools.Utils.csproj", "{2E93D12A-139B-46B8-BED3-294E714C6D6A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PDTools.Utils", "PDTools\PDTools.Utils\PDTools.Utils.csproj", "{CB23A95C-D677-4EC3-97C3-E065E6309C9C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -17,10 +17,10 @@ Global
{635F7BAF-FCAE-4EB7-B2B1-ED8BC060D64C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{635F7BAF-FCAE-4EB7-B2B1-ED8BC060D64C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{635F7BAF-FCAE-4EB7-B2B1-ED8BC060D64C}.Release|Any CPU.Build.0 = Release|Any CPU
{2E93D12A-139B-46B8-BED3-294E714C6D6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E93D12A-139B-46B8-BED3-294E714C6D6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E93D12A-139B-46B8-BED3-294E714C6D6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E93D12A-139B-46B8-BED3-294E714C6D6A}.Release|Any CPU.Build.0 = Release|Any CPU
{CB23A95C-D677-4EC3-97C3-E065E6309C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB23A95C-D677-4EC3-97C3-E065E6309C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB23A95C-D677-4EC3-97C3-E065E6309C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB23A95C-D677-4EC3-97C3-E065E6309C9C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion GTPSPVolTools/GTPSPVolTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PDTools.Utils\PDTools.Utils.csproj" />
<ProjectReference Include="..\PDTools\PDTools.Utils\PDTools.Utils.csproj" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion GTPSPVolTools/IndexEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class IndexEntry
public void Read(ref BitStream bs)
{
byte subDirIndexMajor = bs.ReadByte();
Indexer = bs.ReadVarPrefixString();
Indexer = bs.ReadVarPrefixStringAlt();

SubDirIndex = (short)((subDirIndexMajor << 8) | bs.ReadByte());
}
Expand Down
1 change: 1 addition & 0 deletions GTPSPVolTools/Packing/IndexWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public void Write(ref BitStream stream)
entryWriter.WriteByte((byte)(_indices[i].EntriesLocationSegmentIndex >> 8)); // Major 8 bits
entryWriter.WriteVarPrefixString(_indices[i].Name);
entryWriter.WriteByte((byte)(_indices[i].EntriesLocationSegmentIndex & 0xFF)); // Minor 8 bits
entryWriter.AlignToNextByte();
}

stream.WriteBoolBit(true); // Index Block
Expand Down
19 changes: 15 additions & 4 deletions GTPSPVolTools/Packing/VolumeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void Build(string outputFile)

// Write all the file & directory entries
Span<byte> toc = WriteToC();
VolumeCrypto.EncryptHeaderPart(toc, toc, toc.Length);
VolumeCrypto.EncryptHeaderPart(toc, toc.Slice(0x04), toc.Length - 4); // Magic is not encrypted
fsVol.Write(toc);

// Merge toc and file blob.
Expand All @@ -91,6 +91,10 @@ public void Build(string outputFile)
byte[] buffer = new byte[0x20000];
while ((count = fs.Read(buffer, 0, buffer.Length)) > 0)
volStream.BaseStream.Write(buffer, 0, count);

// Just incase. There's a value in the header with the number of 0x10000 data chunks
// Original is encrypted padding, personally I say we don't care for it
volStream.BaseStream.Align(0x10000, grow: true);
}
catch (Exception e)
{
Expand Down Expand Up @@ -152,9 +156,11 @@ private Span<byte> WriteToC()

// Write volume header, append toc writen above to it
BitStream headerStream = new BitStream(BitStreamMode.Write, endian: BitStreamSignificantBitOrder.MSB);
headerStream.WriteUInt32(0x21315815);
uint serial = (uint)(DateTime.UtcNow - new DateTime(2001, 1, 1)).TotalSeconds;
headerStream.WriteUInt32(Volume.VolumeMagic);
headerStream.WriteUInt32(0xDEADBEEF);
headerStream.WriteUInt64(0);
headerStream.WriteUInt32(serial);
headerStream.WriteUInt32(0);
headerStream.WriteUInt32(0); // Toc Block Offset - 0 means it's at 0x800 (1 * 0x800) + (offset * 0x800)

const int baseTocPos = 0x800;
Expand All @@ -163,11 +169,14 @@ private Span<byte> WriteToC()
headerStream.Align(BlockSize);
int fileDataOffset = headerStream.Position;

long totalDataSize = new FileInfo("gtfiles.temp").Length;
uint totalDataSize0x10000Chunks = MiscUtils.AlignValue((uint)totalDataSize, 0x10000);

headerStream.Position = 0x14;
headerStream.WriteUInt32((uint)(fileDataOffset - baseTocPos) / BlockSize);
headerStream.WriteUInt32((uint)_segmentOffsets.Count + 1u);
headerStream.WriteUInt32((uint)tocStream.Length);
headerStream.WriteInt32(0x3EBF);
headerStream.WriteUInt32(totalDataSize0x10000Chunks / 0x10000);

return headerStream.GetBuffer();
}
Expand Down Expand Up @@ -276,6 +285,8 @@ private void WriteDirEntryToCSegment(ref BitStream stream, VolumeEntry folder)
// Write index segment (if exists)
if (!indexWriter.IsEmpty)
{
stream.AlignToNextByte();

_segmentOffsets.Add((uint)stream.Position);
indexWriter.Write(ref stream);
}
Expand Down
2 changes: 1 addition & 1 deletion GTPSPVolTools/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ static void Unpack(UnpackVerbs verbs)
}

var volume = new Volume(verbs.InputPath);
if (!volume.Init())
if (!volume.Init(verbs.SaveVolumeHeaderToc))
{
Console.WriteLine("ERROR: Could not read volume.");
return;
Expand Down
84 changes: 58 additions & 26 deletions GTPSPVolTools/Volume.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,35 @@ public class Volume

public const int VolumeMagic = 0x71D319F3;

public long Date { get; set; }
public long SerialDate { get; set; }

/// <summary>
/// Offset of the toc in blocks, starting from header
/// </summary>
public int ToCBlockOffset { get; set; }
public int FileDataOffset { get; set; }

/// <summary>
/// From start of toc end
/// </summary>
public int FileDataBlockOffset { get; set; }

/// <summary>
/// Number of folders in the file system
/// </summary>
public int FolderCount { get; set; }

/// <summary>
/// In actual bytes
/// </summary>
public int ToCLength { get; set; }
public int UnkSize { get; set; }

/// <summary>
/// Data size as a number of 0x10000 chunks, starting from data offset.
/// </summary>
public int TotalDataSize { get; set; }

public long ToCActualOffset { get; set; }
public long DataActualOffset { get; set; }

public List<ushort> FolderOffsets { get; set; }

Expand All @@ -39,44 +60,55 @@ public Volume(string fileName)
_fileName = fileName;
}

// 8b12d6c
public bool Init(bool saveVolumeHeaderToc = false)
{
_fs = File.Open(_fileName, FileMode.Open);

Span<byte> buf = new byte[0x40];
_fs.Read(buf);

// 30ed6c
VolumeCrypto.DecryptHeaderPart(buf[0x04..], buf[0x04..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x08..], buf[0x08..], sizeof(long));
VolumeCrypto.DecryptHeaderPart(buf[0x10..], buf[0x10..], sizeof(uint)); // Block Size
VolumeCrypto.DecryptHeaderPart(buf[0x14..], buf[0x14..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x18..], buf[0x18..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x1c..], buf[0x1c..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x20..], buf[0x20..], sizeof(uint));

SpanReader sr = new SpanReader(buf);
int Magic = sr.ReadInt32();

if (Magic != VolumeMagic)
if (Magic != VolumeMagic) // or 0x515111d3? volume is handled *slightly* differently if that's the magic
{
Console.WriteLine("Volume: Magic did not match. Not a volume file.");
return false;
}

Date = sr.ReadInt64();
int unk3 = sr.ReadInt32();
VolumeCrypto.DecryptHeaderPart(buf[0x04..], buf[0x04..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x08..], buf[0x08..], sizeof(long));
VolumeCrypto.DecryptHeaderPart(buf[0x10..], buf[0x10..], sizeof(uint)); // Block Size
VolumeCrypto.DecryptHeaderPart(buf[0x14..], buf[0x14..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x18..], buf[0x18..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x1c..], buf[0x1c..], sizeof(uint));
VolumeCrypto.DecryptHeaderPart(buf[0x20..], buf[0x20..], sizeof(uint));

uint deadbeef = sr.ReadUInt32(); // Unused
SerialDate = sr.ReadUInt32();
int unk3 = sr.ReadInt32(); // Unused
ToCBlockOffset = sr.ReadInt32();
FileDataOffset = sr.ReadInt32();
FileDataBlockOffset = sr.ReadInt32();
FolderCount = sr.ReadInt32();
ToCLength = sr.ReadInt32();
UnkSize = sr.ReadInt32(); // + 7 >> 3
TotalDataSize = sr.ReadInt32();

// Calculate offsets
ToCActualOffset = (MainHeaderBlockSize + ToCBlockOffset) * BlockSize;
DataActualOffset = (MainHeaderBlockSize + ToCBlockOffset + FileDataBlockOffset) * BlockSize;

_fs.Position = ToCActualOffset;

//Console.WriteLine($"Volume: Created - {Date}");
Console.WriteLine($"Volume: {FolderCount} Total Folders");
Console.WriteLine($"Volume Header:");
Console.WriteLine($"- Serial Date: {SerialDate} ({new DateTime(2001, 1, 1) + TimeSpan.FromSeconds(SerialDate)})");
Console.WriteLine($"- ToC Block Offset: {ToCBlockOffset}");
Console.WriteLine($"- File Data Block Offset: {FileDataBlockOffset}");
Console.WriteLine($"- Folder Count: {FolderCount}");
Console.WriteLine($"- ToC Length: 0x{ToCLength:X8}");
Console.WriteLine($"- Num Data Chunks: 0x{TotalDataSize:X8} (0x{TotalDataSize:X8} * 0x10000 = Total Data Size is {TotalDataSize * 0x10000:X8}/{TotalDataSize * 0x10000} bytes)");
Console.WriteLine($"- Actual ToC Offset: 0x{ToCActualOffset:X8}");
Console.WriteLine($"- Actual Data Start Offset: 0x{DataActualOffset:X8}");

if (saveVolumeHeaderToc)
{
Expand Down Expand Up @@ -105,7 +137,7 @@ public bool Init(bool saveVolumeHeaderToc = false)
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
// 30f568
// 8b13568
private VolumeEntry Find(string path)
{
Span<byte> parentEntry = GetFolderPtr(0, 0); // Root
Expand Down Expand Up @@ -159,7 +191,7 @@ private VolumeEntry Find(string path)
return null;
}

// 30f1c4
// 8b131c4
private Span<byte> GetFolderPtr(int folderIndex, int idk)
{
int current = FolderOffsets[folderIndex];
Expand All @@ -173,7 +205,7 @@ private Span<byte> GetFolderPtr(int folderIndex, int idk)

}

// 30EAB8
// 8b12ab8
public Span<byte> SearchEntryInFolder(Span<byte> folderPtr, ReadOnlySpan<char> targetStr, int targetStrLen)
{
short dirBits = (short)(VolumeCrypto.SBOX_DECRYPT[folderPtr[0]] | VolumeCrypto.SBOX_DECRYPT[folderPtr[1]] << 8);
Expand Down Expand Up @@ -251,7 +283,7 @@ public Span<byte> SearchEntryInFolder(Span<byte> folderPtr, ReadOnlySpan<char> t
return null;
}

// 30ea1c
// 8b12a1c
private Span<byte> GetNodeEntry(Span<byte> folderPtr, int entryIndex)
{
if (entryIndex <= 0)
Expand All @@ -271,7 +303,7 @@ private Span<byte> GetNodeEntry(Span<byte> folderPtr, int entryIndex)
}
}

// 30DC4C
// 8b11c4c
private int GetVarInt(Span<byte> inPtr, out Span<byte> outPtr)
{
int lSize = 0;
Expand All @@ -291,7 +323,7 @@ private int GetVarInt(Span<byte> inPtr, out Span<byte> outPtr)
return lTemp;
}

// 30df60
// 8b11f60
private Span<byte> SeekEntryPtrToEntryInfo(Span<byte> inPtr)
{
Span<byte> tmp = inPtr[1..]; // Skip entry first byte bits
Expand Down Expand Up @@ -416,7 +448,7 @@ private void RegisterFolder(ref BitStream bs, VolumeEntry parent, string parentP

private void UnpackFile(string outputDir, VolumeEntry entry)
{
uint fileOffset = (uint)((1 + this.ToCBlockOffset + this.FileDataOffset) * BlockSize) + entry.FileOffset;
long fileOffset = (long)(DataActualOffset + entry.FileOffset);
_fs.Position = fileOffset;

byte[] data = new byte[entry.CompressedSize];
Expand Down
8 changes: 4 additions & 4 deletions GTPSPVolTools/VolumeCrypto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace GTPSPVolTools
{
public class VolumeCrypto
{
// 48e580
// 8c92580
public static byte[] SBOX_DECRYPT = new byte[]
{
0x0, 0x6, 0x86, 0x57, 0x97, 0x69, 0x6C, 0xB5, 0xBD, 0xD6, 0xBE, 0x34, 0xC2, 0x35, 0xCE, 0xFA,
Expand Down Expand Up @@ -40,7 +40,7 @@ static VolumeCrypto()
SBOX_ENCRYPT[SBOX_DECRYPT[i]] = (byte)i;
}

// 30dc10
// 8b11c10
public static void DecryptHeaderPart(Span<byte> buffer, Span<byte> outBuffer, int size)
{
for (int i = 0; i < size; i++)
Expand All @@ -53,8 +53,8 @@ public static void EncryptHeaderPart(Span<byte> buffer, Span<byte> outBuffer, in
outBuffer[i] = SBOX_ENCRYPT[buffer[i]];
}

// 30f7ac
public static void DecryptFile(uint fileOffset, Span<byte> data, int nSize)
// 8b137ac
public static void DecryptFile(long fileOffset, Span<byte> data, int nSize)
{
byte dOffset = (byte)fileOffset;
Span<byte> currentBuffer = data;
Expand Down
2 changes: 1 addition & 1 deletion GTPSPVolTools/VolumeEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void Read(ref BitStream bs)

int subFolderIndexMajor = (int)bs.ReadBits(6);

Name = bs.ReadVarPrefixString();
Name = bs.ReadVarPrefixStringAlt();


if (Type == EntryType.Directory)
Expand Down
1 change: 1 addition & 0 deletions PDTools
Submodule PDTools added at 9a94c3
Loading

0 comments on commit 99b0932

Please sign in to comment.