Skip to content
This repository has been archived by the owner on Jan 23, 2022. It is now read-only.

Commit

Permalink
add rrtex converter, make chunky reader more general (#1)
Browse files Browse the repository at this point in the history
* add rrtex converter, make chunky reader more general

* fix rgd viewer and json converter

* use imagesharp file writer
  • Loading branch information
RobinKa authored Nov 23, 2021
1 parent d624e48 commit ee66061
Show file tree
Hide file tree
Showing 17 changed files with 586 additions and 221 deletions.
14 changes: 14 additions & 0 deletions ChunkyHeaderReaderCLI/ChunkyHeaderReaderCLI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\RGDReader\RGDReader.csproj" />
</ItemGroup>

</Project>
36 changes: 36 additions & 0 deletions ChunkyHeaderReaderCLI/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using RGDReader;
using System.Text;

if (args.Length != 1)
{
Console.WriteLine("Usage: {0} <File Path>", AppDomain.CurrentDomain.FriendlyName);
return;
}

string rgdPath = args[0];

var reader = new ChunkyFileReader(File.Open(rgdPath, FileMode.Open), Encoding.ASCII);
var fileHeader = reader.ReadChunkyFileHeader();
Console.WriteLine("File header version: {0}", fileHeader.Version);

void PrintHeaders(long position, long length, int depth = 0)
{
reader.BaseStream.Position = position;
foreach (var header in reader.ReadChunkHeaders(length))
{
for (int i = 0; i < depth; i++)
{
Console.Write("\t");
}

Console.WriteLine("Chunk Type: {0}, Name: {1}, Data length: {2}, Data position: {3}, Version: {4}, Path: {5}",
header.Type, header.Name, header.Length, header.DataPosition, header.Version, header.Path);

if (header.Type == "FOLD")
{
PrintHeaders(header.DataPosition, header.Length, depth + 1);
}
}
}

PrintHeaders(reader.BaseStream.Position, reader.BaseStream.Length - reader.BaseStream.Position);
112 changes: 44 additions & 68 deletions RGDJSONConverter/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,104 +26,80 @@ void ConvertRGD(string rgdPath)
var outRelativePath = Path.ChangeExtension(relativePath, "json");
var outJsonPath = Path.Join(outPath, outRelativePath);

using var reader = new ChunkyFileReader(File.Open(rgdPath, FileMode.Open), Encoding.ASCII);
var nodes = ChunkyUtil.ReadRGD(rgdPath);

var fileHeader = reader.ReadChunkyFileHeader();

KeyValueDataChunk? kvs = null;
KeysDataChunk? keys = null;

while (reader.BaseStream.Position < reader.BaseStream.Length)
StringBuilder stringBuilder = new StringBuilder();
void printIndent(int indent)
{
var chunkHeader = reader.ReadChunkHeader();
if (chunkHeader.Type == "DATA")
for (int i = 0; i < indent; i++)
{
if (chunkHeader.Name == "AEGD")
{
kvs = reader.ReadKeyValueDataChunk(chunkHeader.Length);
}

if (chunkHeader.Name == "KEYS")
{
keys = reader.ReadKeysDataChunk();
break;
}
stringBuilder.Append(" ");
}
}


if (kvs != null && keys != null)
void printValue(RGDNode node, int depth)
{
var keysInv = ChunkyUtil.ReverseReadOnlyDictionary(keys.StringKeys);
printIndent(depth);
stringBuilder.Append("{\n");
printIndent(depth + 1);
stringBuilder.AppendFormat("\"key\": \"{0}\",\n", node.Key);
printIndent(depth + 1);
stringBuilder.Append("\"value\": ");

StringBuilder stringBuilder = new StringBuilder();
void printIndent(int indent)
{
for (int i = 0; i < indent; i++)
{
stringBuilder.Append(" ");
}
}

void printTable(IList<(ulong Key, int Type, object Value)> table, int indent)
if (node.Value is IList<RGDNode> childNodes)
{
stringBuilder.Append("[\n");

for (int i = 0; i < table.Count; i++)
for (int i = 0; i < childNodes.Count; i++)
{
var (childKey, childType, childValue) = table[i];

printIndent(indent);
stringBuilder.Append("{\n");

printIndent(indent + 1);
stringBuilder.AppendFormat("\"key\": \"{0}\",\n", keysInv[childKey]);
printIndent(indent + 1);
stringBuilder.Append("\"value\": ");
printValue(childType, childValue, indent + 1);
printValue(childNodes[i], depth + 2);
var childNode = childNodes[i];

printIndent(indent);
stringBuilder.Append("}");
if (i != table.Count - 1)
if (i != childNodes.Count - 1)
{
stringBuilder.Append(",");
}

stringBuilder.Append("\n");
}

printIndent(indent - 1);
printIndent(depth + 1);
stringBuilder.Append("]");
stringBuilder.Append("\n");
}

void printValue(int type, object value, int indent)
else
{
if (value is IList<(ulong Key, int Type, object Value)> table)
{
printTable(table, indent + 1);
}
else
stringBuilder.Append(node.Value switch
{
stringBuilder.AppendFormat("{0}", type switch
{
2 => (bool)value ? "true" : "false",
3 => $"\"{((string)value).Replace("\\", "\\\\")}\"",
_ => value,
});
bool b => b ? "true" : "false",
string s => $"\"{s.Replace("\\", "\\\\")}\"",
_ => node.Value,
});

stringBuilder.Append("\n");
}
stringBuilder.Append("\n");
}

stringBuilder.Append("{\n");
printIndent(1);
stringBuilder.Append("\"data\": ");
printTable(kvs.KeyValues, 2);
printIndent(depth);
stringBuilder.Append("}");
}

Directory.CreateDirectory(Path.GetDirectoryName(outJsonPath));
File.WriteAllText(outJsonPath, stringBuilder.ToString());
stringBuilder.Append("{\n");
printIndent(1);
stringBuilder.Append("\"data\": [\n");
for (int i = 0; i < nodes.Count; i++)
{
printValue(nodes[i], 2);
if (i != nodes.Count - 1)
{
stringBuilder.Append(",");
}
stringBuilder.Append("\n");
}
printIndent(1);
stringBuilder.Append("]\n}");

Directory.CreateDirectory(Path.GetDirectoryName(outJsonPath));
File.WriteAllText(outJsonPath, stringBuilder.ToString());
}

using (var progress = new ProgressBar())
Expand Down
14 changes: 13 additions & 1 deletion RGDReader.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGDJSONConverter", "RGDJSONConverter\RGDJSONConverter.csproj", "{6CE167A1-D33F-44D8-88EB-2B2E978969B5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGDJSONConverter", "RGDJSONConverter\RGDJSONConverter.csproj", "{6CE167A1-D33F-44D8-88EB-2B2E978969B5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChunkyHeaderReaderCLI", "ChunkyHeaderReaderCLI\ChunkyHeaderReaderCLI.csproj", "{CB3717F1-52D3-4A22-B815-CA3B846DD041}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RRTexConverter", "RRTexConverter\RRTexConverter.csproj", "{8F120438-7BE3-4890-99BB-57B7E5CED883}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -38,6 +42,14 @@ Global
{6CE167A1-D33F-44D8-88EB-2B2E978969B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CE167A1-D33F-44D8-88EB-2B2E978969B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CE167A1-D33F-44D8-88EB-2B2E978969B5}.Release|Any CPU.Build.0 = Release|Any CPU
{CB3717F1-52D3-4A22-B815-CA3B846DD041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB3717F1-52D3-4A22-B815-CA3B846DD041}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB3717F1-52D3-4A22-B815-CA3B846DD041}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB3717F1-52D3-4A22-B815-CA3B846DD041}.Release|Any CPU.Build.0 = Release|Any CPU
{8F120438-7BE3-4890-99BB-57B7E5CED883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F120438-7BE3-4890-99BB-57B7E5CED883}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F120438-7BE3-4890-99BB-57B7E5CED883}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F120438-7BE3-4890-99BB-57B7E5CED883}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion RGDReader/ChunkHeader.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace RGDReader;

public record class ChunkHeader(string Type, string Name, int Version, int Length, int MinVersion);
public record class ChunkHeader(string Type, string Name, int Version, int Length, string Path, long DataPosition);
50 changes: 34 additions & 16 deletions RGDReader/ChunkyFileReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,33 @@ public ChunkyFileReader(Stream input, Encoding encoding, bool leaveOpen) : base(
{
}

public IEnumerable<ChunkHeader> ReadChunkHeaders(long length)
{
long startPosition = BaseStream.Position;
while (BaseStream.Position < startPosition + length)
{
var chunkHeader = ReadChunkHeader();

yield return chunkHeader;

BaseStream.Position = chunkHeader.DataPosition + chunkHeader.Length;
}
}

public IEnumerable<ChunkHeader> ReadChunkHeaders()
{
return ReadChunkHeaders(BaseStream.Length - BaseStream.Position);
}

public ChunkHeader ReadChunkHeader()
{
return new ChunkHeader(
new string(ReadChars(4)),
new string(ReadChars(4)),
ReadInt32(),
ReadInt32(),
ReadInt32()
Encoding.ASCII.GetString(ReadBytes(ReadInt32())),
BaseStream.Position
);
}

Expand Down Expand Up @@ -62,54 +81,53 @@ private object ReadType(int type)
1 => ReadInt32(),
2 => ReadBoolean(),
3 => ReadCString(),
100 => ReadTable(),
101 => ReadTable(),
100 => ReadChunkyList(),
101 => ReadChunkyList(),
_ => throw new Exception($"Unknown type {type}")
};
}

private List<(ulong Key, int Type, object Value)> ReadTable()
private ChunkyList ReadChunkyList()
{
int length = ReadInt32();

// Read table index
List<(ulong key, int Type, int index)> keyTypeAndDataIndex = new();
var keyTypeAndDataIndex = new (ulong key, int Type, int index)[length];
for (int i = 0; i < length; i++)
{
ulong key = ReadUInt64();
int type = ReadInt32();
int index = ReadInt32();
keyTypeAndDataIndex.Add((key, type, index));
keyTypeAndDataIndex[i] = (key, type, index);
}

// Read table row data
long dataPosition = BaseStream.Position;

List<(ulong Key, int Type, object Value)> kvs = new();
ChunkyList kvs = new();
foreach (var (key, type, index) in keyTypeAndDataIndex)
{
BaseStream.Position = dataPosition + index;
kvs.Add((key, type, ReadType(type)));
kvs.Add(new KeyValueEntry(key, ReadType(type)));
}

return kvs;
}

public KeyValueDataChunk ReadKeyValueDataChunk(int length)
public KeyValueDataChunk ReadKeyValueDataChunk(ChunkHeader header)
{
long startPosition = BaseStream.Position;

int unknown2 = ReadInt32();
BaseStream.Position = header.DataPosition;

var table = ReadTable();

BaseStream.Position = startPosition + length;
int unknown = ReadInt32();
var table = ReadChunkyList();

return new KeyValueDataChunk(table);
}

public KeysDataChunk ReadKeysDataChunk()
public KeysDataChunk ReadKeysDataChunk(ChunkHeader header)
{
BaseStream.Position = header.DataPosition;

Dictionary<string, ulong> stringKeys = new();

int count = ReadInt32();
Expand Down
15 changes: 15 additions & 0 deletions RGDReader/ChunkyList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace RGDReader;
public class ChunkyList : List<KeyValueEntry>
{
public ChunkyList()
{
}

public ChunkyList(IEnumerable<KeyValueEntry> collection) : base(collection)
{
}

public ChunkyList(int capacity) : base(capacity)
{
}
}
Loading

0 comments on commit ee66061

Please sign in to comment.