Skip to content

Commit

Permalink
Bug fix to correctly write XSEQ;
Browse files Browse the repository at this point in the history
Properly resolve hash values to handle hash collisions;
  • Loading branch information
onepiecefreak3 committed Sep 25, 2024
1 parent 0b5770b commit 906e544
Show file tree
Hide file tree
Showing 21 changed files with 217 additions and 217 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,10 @@ private void PrintHelp()
Console.WriteLine("Following commands exist:");
Console.WriteLine(" -h, --help\t\tShows this help message.");
Console.WriteLine(" -o, --operation\tThe operation to take on the file");
Console.WriteLine(" Valid operations are: e for extraction, c for creation, d for decompression");
Console.WriteLine(" -t, --type\t\tThe type of file given");
Console.WriteLine(" Valid types are: xq32, xseq");
Console.WriteLine(" The type is automatically detected when extracting; This argument will not have any effect on operation 'e'");
Console.WriteLine(" Valid operations are: e for extraction, c for creation, d for decompression");
Console.WriteLine(" -f, --file\t\tThe file to process");
Console.WriteLine(" -n, --no-compression\t[Optional] If the file uses a compression layer");
Console.WriteLine(" This option is automatically detected when extracting; This argument will not have any effect on operation 'e'");
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface IScriptReader
IList<ScriptFunction> ReadFunctions(ScriptTable functionTable, ScriptStringTable? stringTable);
IList<ScriptJump> ReadJumps(ScriptTable jumpTable, ScriptStringTable? stringTable);
IList<ScriptInstruction> ReadInstructions(ScriptTable instructionTable);
IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, ScriptStringTable? stringTable);
IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, ScriptTable instructionTable, ScriptStringTable? stringTable);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface IStringTable
string Read(long offset);
long Write(string value);

string GetByHash(uint hash);
IList<string> GetByHash(uint hash);
uint ComputeHash(string value);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public interface IXq32ScriptReader : IScriptReader
IList<ScriptFunction> CreateFunctions(IReadOnlyList<Xq32Function> functions, ScriptStringTable? stringTable = null);
IList<ScriptJump> CreateJumps(IReadOnlyList<Xq32Jump> jumps, ScriptStringTable? stringTable = null);
IList<ScriptInstruction> CreateInstructions(IReadOnlyList<Xq32Instruction> instructions);
IList<ScriptArgument> CreateArguments(IReadOnlyList<Xq32Argument> arguments, ScriptStringTable? stringTable = null);
IList<ScriptArgument> CreateArguments(IReadOnlyList<Xq32Argument> arguments, IReadOnlyList<ScriptInstruction> instructions, ScriptStringTable? stringTable = null);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public interface IXseqScriptReader : IScriptReader
IList<ScriptFunction> CreateFunctions(IReadOnlyList<XseqFunction> functions, ScriptStringTable? stringTable = null);
IList<ScriptJump> CreateJumps(IReadOnlyList<XseqJump> jumps, ScriptStringTable? stringTable = null);
IList<ScriptInstruction> CreateInstructions(IReadOnlyList<XseqInstruction> instructions);
IList<ScriptArgument> CreateArguments(IReadOnlyList<XseqArgument> arguments, ScriptStringTable? stringTable = null);
IList<ScriptArgument> CreateArguments(IReadOnlyList<XseqArgument> arguments, IReadOnlyList<ScriptInstruction> instructions, ScriptStringTable? stringTable = null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public ScriptFile Read(ScriptContainer container)
IList<ScriptFunction> functions = ReadFunctions(container.FunctionTable, container.StringTable, length!.Value);
IList<ScriptJump> jumps = ReadJumps(container.JumpTable, container.StringTable, length!.Value);
IList<ScriptInstruction> instructions = ReadInstructions(container.InstructionTable, length!.Value);
IList<ScriptArgument> arguments = ReadArguments(container.ArgumentTable, container.StringTable, length!.Value);
IList<ScriptArgument> arguments = ReadArguments(container.ArgumentTable, instructions.AsReadOnly(), container.StringTable, length!.Value);

return new ScriptFile
{
Expand Down Expand Up @@ -69,12 +69,12 @@ public IList<ScriptInstruction> ReadInstructions(ScriptTable instructionTable)
return ReadInstructions(instructionTable, length!.Value);
}

public IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, ScriptStringTable? stringTable)
public IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, ScriptTable instructionTable, ScriptStringTable? stringTable)
{
if (!TryDetectTablePointerLength(argumentTable, _entrySizeProvider.GetArgumentEntrySize, out PointerLength? length))
throw new InvalidOperationException("Could not detect pointer length.");

return ReadArguments(argumentTable, stringTable, length!.Value);
return ReadArguments(argumentTable, instructionTable, stringTable, length!.Value);
}

public abstract IReadOnlyList<TFunction> ReadFunctions(Stream functionStream, int entryCount, PointerLength length);
Expand Down Expand Up @@ -119,60 +119,69 @@ public IList<ScriptInstruction> CreateInstructions(IReadOnlyList<TInstruction> i
return result;
}

public IList<ScriptArgument> CreateArguments(IReadOnlyList<TArgument> arguments, ScriptStringTable? stringTable = null)
public IList<ScriptArgument> CreateArguments(IReadOnlyList<TArgument> arguments, IReadOnlyList<ScriptInstruction> instructions, ScriptStringTable? stringTable = null)
{
using IBinaryReaderX? stringReader = stringTable == null ? null : _binaryFactory.CreateReader(stringTable.Stream, true);

var result = new ScriptArgument[arguments.Count];

var instructionTypes = new (int, int)[arguments.Count];
foreach (ScriptInstruction instruction in instructions)
{
for (var i = 0; i < instruction.ArgumentCount; i++)
instructionTypes[instruction.ArgumentIndex + i] = (instruction.Type, i);
}

var counter = 0;
foreach (TArgument argument in arguments)
result[counter++] = CreateArgument(argument, stringReader);
{
(int instructionType, int argumentIndex) = instructionTypes[counter];
result[counter++] = CreateArgument(argument, instructionType, argumentIndex, stringReader);
}

return result;
}

protected abstract ScriptFunction CreateFunction(TFunction function, IBinaryReaderX? stringReader);
protected abstract ScriptJump CreateJump(TJump jump, IBinaryReaderX? stringReader);
protected abstract ScriptInstruction CreateInstruction(TInstruction instruction);
protected abstract ScriptArgument CreateArgument(TArgument argument, IBinaryReaderX? stringReader);
protected abstract ScriptArgument CreateArgument(TArgument argument, int instructionType, int argumentIndex, IBinaryReaderX? stringReader);

protected abstract IEnumerable<TFunction> OrderFunctions(IReadOnlyList<TFunction> functions);

private IList<ScriptFunction> ReadFunctions(ScriptTable functionTable, ScriptStringTable? stringTable, PointerLength length)
{
using IBinaryReaderX br = _binaryFactory.CreateReader(functionTable.Stream, true);

IReadOnlyList<TFunction> functions = ReadFunctions(functionTable.Stream, functionTable.EntryCount, length);

return CreateFunctions(functions, stringTable);
}

private IList<ScriptJump> ReadJumps(ScriptTable jumpTable, ScriptStringTable? stringTable, PointerLength length)
{
using IBinaryReaderX br = _binaryFactory.CreateReader(jumpTable.Stream, true);

IReadOnlyList<TJump> jumps = ReadJumps(jumpTable.Stream, jumpTable.EntryCount, length);

return CreateJumps(jumps, stringTable);
}

private IList<ScriptInstruction> ReadInstructions(ScriptTable instructionTable, PointerLength length)
{
using IBinaryReaderX br = _binaryFactory.CreateReader(instructionTable.Stream, true);

IReadOnlyList<TInstruction> instructions = ReadInstructions(instructionTable.Stream, instructionTable.EntryCount, length);

return CreateInstructions(instructions);
}

private IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, ScriptStringTable? stringTable, PointerLength length)
private IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, ScriptTable instructionTable, ScriptStringTable? stringTable, PointerLength length)
{
using IBinaryReaderX br = _binaryFactory.CreateReader(argumentTable.Stream, true);
IList<ScriptInstruction> instructions = ReadInstructions(instructionTable, length);

return ReadArguments(argumentTable, instructions.AsReadOnly(), stringTable, length);
}

private IList<ScriptArgument> ReadArguments(ScriptTable argumentTable, IReadOnlyList<ScriptInstruction> instructions, ScriptStringTable? stringTable, PointerLength length)
{
IReadOnlyList<TArgument> arguments = ReadArguments(argumentTable.Stream, argumentTable.EntryCount, length);

return CreateArguments(arguments, stringTable);
return CreateArguments(arguments, instructions, stringTable);
}

private bool TryDetectPointerLength(ScriptContainer container, out PointerLength? length)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ namespace Logic.Domain.Level5.Script.Xq32
internal class Xq32ScriptReader : ScriptReader<Xq32Function, Xq32Jump, Xq32Instruction, Xq32Argument>, IXq32ScriptReader
{
private readonly IBinaryFactory _binaryFactory;
private readonly IXq32ScriptHashStringCache _cache;
private readonly Dictionary<uint, IList<string>> _functionCache;
private readonly Dictionary<uint, IList<string>> _jumpCache;

public Xq32ScriptReader(IXq32ScriptDecompressor decompressor, IXq32ScriptHashStringCache cache,
IXq32ScriptEntrySizeProvider entrySizeProvider, IBinaryFactory binaryFactory)
public Xq32ScriptReader(IXq32ScriptDecompressor decompressor, IXq32ScriptEntrySizeProvider entrySizeProvider,
IBinaryFactory binaryFactory)
: base(decompressor, entrySizeProvider, binaryFactory)
{
_binaryFactory = binaryFactory;
_cache = cache;
_functionCache = new Dictionary<uint, IList<string>>();
_jumpCache = new Dictionary<uint, IList<string>>();
}

public override IReadOnlyList<Xq32Function> ReadFunctions(Stream functionStream, int entryCount, PointerLength length)
Expand Down Expand Up @@ -183,7 +185,10 @@ protected override ScriptFunction CreateFunction(Xq32Function function, IBinaryR
stringReader.BaseStream.Position = function.nameOffset;
name = stringReader.ReadCStringSJIS();

_cache.Set(function.crc32, name);
if (!_functionCache.TryGetValue(function.crc32, out IList<string>? functionNames))
_functionCache[function.crc32] = functionNames = new List<string>();

functionNames.Add(name);
}

return new ScriptFunction
Expand Down Expand Up @@ -211,7 +216,10 @@ protected override ScriptJump CreateJump(Xq32Jump jump, IBinaryReaderX? stringRe
stringReader.BaseStream.Position = jump.nameOffset;
name = stringReader.ReadCStringSJIS();

_cache.Set(jump.crc32, name);
if (!_jumpCache.TryGetValue(jump.crc32, out IList<string>? jumpNames))
_jumpCache[jump.crc32] = jumpNames = new List<string>();

jumpNames.Add(name);
}

return new ScriptJump
Expand All @@ -235,7 +243,7 @@ protected override ScriptInstruction CreateInstruction(Xq32Instruction instructi
};
}

protected override ScriptArgument CreateArgument(Xq32Argument argument, IBinaryReaderX? stringReader)
protected override ScriptArgument CreateArgument(Xq32Argument argument, int instructionType, int argumentIndex, IBinaryReaderX? stringReader)
{
int rawType = -1;
ScriptArgumentType type;
Expand All @@ -252,8 +260,36 @@ protected override ScriptArgument CreateArgument(Xq32Argument argument, IBinaryR
type = ScriptArgumentType.StringHash;
value = argument.value;

if (_cache.TryGet(argument.value, out string name))
value = name;
if (argumentIndex != 0)
{
if (_functionCache.TryGetValue((ushort)argument.value, out IList<string>? names)
|| _jumpCache.TryGetValue((ushort)argument.value, out names))
value = names.First();
break;
}

switch (instructionType)
{
case 20:
if (_functionCache.TryGetValue((ushort)argument.value, out IList<string>? names))
value = names.First();
break;

case 30:
if (_jumpCache.TryGetValue((ushort)argument.value, out names))
value = names.First();
break;

case 31:
if (_jumpCache.TryGetValue((ushort)argument.value, out names))
value = names.First();
break;

case 33:
if (_jumpCache.TryGetValue((ushort)argument.value, out names))
value = names.First();
break;
}

break;

Expand Down
Loading

0 comments on commit 906e544

Please sign in to comment.