Skip to content

Instantly share code, notes, and snippets.

@hayleyxyz
Last active April 6, 2025 16:05
Show Gist options
  • Save hayleyxyz/0c344bddb8fb570f83069b283a7b6a47 to your computer and use it in GitHub Desktop.
Save hayleyxyz/0c344bddb8fb570f83069b283a7b6a47 to your computer and use it in GitHub Desktop.
Indiana Jones and the Great Circle .resource extractor
using System.Text;
namespace indyresources
{
internal class Program
{
static void Main(string[] args)
{
ParseResources(File.OpenRead(@"D:\SteamLibrary\steamapps\common\The Great Circle\base\gameresources_pc.resources"));
}
struct Entry
{
public ulong[] values;
public string name;
public long Offset => (long) values[6];
public int Size => (int) values[7];
}
static void ParseResources(Stream stream)
{
var entries = new List<Entry>();
var stringOffsets = new List<ulong>();
var stringTable = new List<string>();
var block = new byte[0x90];
// Read header
stream.Position = 0;
stream.Read(block, 0, block.Length);
for (int i = 0; i < block.Length / 4; i++)
{
uint value = BitConverter.ToUInt32(block, i * 4);
Console.WriteLine(value.ToString("x8"));
}
// 0x24 in header is number of blocks
stream.Position = 0x24;
stream.Read(block, 0, 8);
var numberOfBlocks = BitConverter.ToInt32(block, 0);
Console.WriteLine($"Number of blocks: {numberOfBlocks} 0x{numberOfBlocks.ToString("x")}");
// 0x30 is the number of entries after the strings
stream.Position = 0x30;
stream.Read(block, 0, 8);
var numberOfPostStringEntries = BitConverter.ToInt32(block, 0);
Console.WriteLine($"Number of post-string entries: {numberOfPostStringEntries} 0x{numberOfPostStringEntries.ToString("x")}");
stream.Position = 0x90;
for (var i = 0; i < numberOfBlocks; i++)
{
var values = new ulong[block.Length / 8];
stream.Read(block, 0, block.Length);
for (var x = 0; x < values.Length; x++)
{
values[x] = BitConverter.ToUInt64(block, x * 8);
}
foreach (var item in values)
{
Console.Write(item.ToString("x16"));
Console.Write(' ');
}
var entry = new Entry();
entry.values = values;
entries.Add(entry);
Console.WriteLine();
}
Console.WriteLine($"End position of last block: {stream.Position}");
// Number of (u)int64s are stored in the last block
var numberOfStringOffsets = entries.Last().values[17];
Console.WriteLine($"Number of string offsets: {numberOfStringOffsets} 0x{numberOfStringOffsets.ToString("x")}");
for (var i = 0u; i < numberOfStringOffsets; i++)
{
stream.Read(block, 0, 8);
var value = BitConverter.ToUInt64(block, 0);
Console.WriteLine($"String offset {i}: {value} 0x{value.ToString("x")}");
stringOffsets.Add(value);
}
Console.WriteLine($"End position of last value: {stream.Position}");
var numberOfStrings = numberOfStringOffsets;
var baseStringOffset = stream.Position;
foreach (var offset in stringOffsets)
{
stream.Position = baseStringOffset + (long) offset;
var str = ReadNullTerminatedString(stream);
Console.WriteLine(str);
stringTable.Add(str);
}
Console.WriteLine($"End position of last string value: {stream.Position}");
// Round the position to the next 8-byte boundary
stream.Position = (stream.Position + 7) & ~7;
for (var i = 0u; i < numberOfPostStringEntries; i++)
{
stream.Read(block, 0, 8);
var value = BitConverter.ToUInt64(block, 0);
Console.WriteLine($"Post-string entry {i}: {value} 0x{value.ToString("x")}");
}
Console.WriteLine($"End position of last value: {stream.Position}");
int index = 1;
foreach (var entry in entries)
{
stream.Position = entry.Offset;
var bytes = new byte[entry.Size];
stream.Read(bytes, 0, entry.Size);
if (! Directory.Exists("extracted"))
Directory.CreateDirectory("extracted");
var ourFilePath = "extracted/" + (index++) + "-" + entry.Offset.ToString("x16") + ".bin";
File.WriteAllBytes(ourFilePath, bytes);
}
}
private static string ReadNullTerminatedString(Stream stream)
{
List<byte> bytes = new List<byte>();
int b;
while ((b = stream.ReadByte()) != -1)
{
if (b == 0x00) // Null terminator found
break;
bytes.Add((byte) b);
}
if (b == -1 && bytes.Count == 0)
throw new Exception("Invalid string at position " + stream.Position);
return Encoding.UTF8.GetString(bytes.ToArray());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment