Mother2GbaTranslation/tools/ScriptTool/Decompiler.cs

194 lines
6.0 KiB
C#
Raw Normal View History

2015-03-16 04:16:12 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ScriptTool
{
2015-03-22 23:55:34 +00:00
class Decompiler : IDecompiler
2015-03-16 04:16:12 +00:00
{
2015-03-22 23:55:34 +00:00
public IEnumerable<IControlCode> ControlCodes { get; set; }
public IDictionary<byte, string> CharLookup { get; set; }
2015-03-16 04:16:12 +00:00
public LabelMap LabelMap { get; set; }
2015-03-22 23:55:34 +00:00
public Func<byte[], int, bool> ControlCodePredicate { get; set; }
2015-03-16 04:16:12 +00:00
2015-03-22 23:55:34 +00:00
public Decompiler(IEnumerable<IControlCode> controlCodes, IDictionary<byte, string> charLookup,
Func<byte[], int, bool> controlCodePredicate)
2015-03-16 04:16:12 +00:00
{
2015-03-22 23:55:34 +00:00
ControlCodes = controlCodes;
CharLookup = charLookup;
ControlCodePredicate = controlCodePredicate;
2015-03-16 04:16:12 +00:00
LabelMap = new LabelMap();
}
public void ScanRange(byte[] rom, int startAddress, int endAddress)
{
if (rom == null)
throw new ArgumentNullException();
int address = startAddress;
while (address < endAddress)
{
2015-03-22 23:55:34 +00:00
if (ControlCodePredicate(rom, address))
2015-03-16 04:16:12 +00:00
{
2015-03-22 23:55:34 +00:00
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(rom, address));
2015-03-16 04:16:12 +00:00
if (code == null)
throw new Exception("Control code not found");
IList<int> references = code.GetReferences(rom, address);
if (references != null)
LabelMap.AddRange(references);
address += code.ComputeLength(rom, address);
}
else
{
address++;
}
}
}
private string FilterCodeString(CodeString codeString)
{
var codeByte = codeString as CodeByte;
if (codeByte != null)
return codeByte.Value.ToString("X2");
2017-03-28 22:31:45 +01:00
int address = ((CodeReference)codeString).Address;
string label;
if (!LabelMap.Labels.TryGetValue(address, out label))
{
label = "????";
}
return "_" + label + "_";
2015-03-16 04:16:12 +00:00
}
public string DecompileRange(byte[] rom, int startAddress, int endAddress, bool newLines)
{
if (rom == null)
throw new ArgumentNullException();
var builder = new StringBuilder();
bool readUntilEnd = (endAddress == -1);
bool ended = false;
2015-03-25 02:02:27 +00:00
bool suppressNextEnd = false;
2015-03-16 04:16:12 +00:00
int address = startAddress;
while (!ended)
{
if (LabelMap.Labels.ContainsKey(address))
{
builder.Append('^');
builder.Append(LabelMap.Labels[address]);
builder.Append('^');
}
2015-03-22 23:55:34 +00:00
if (ControlCodePredicate(rom, address))
2015-03-16 04:16:12 +00:00
{
2015-03-22 23:55:34 +00:00
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(rom, address));
2015-03-16 04:16:12 +00:00
if (code == null)
throw new Exception("Control code not found");
2015-03-22 23:55:34 +00:00
// Check if it's compressed text
if (code.IsCompressedString)
{
builder.Append(code.GetCompressedString(rom, address));
}
else
{
IList<CodeString> codeStrings = code.GetCodeStrings(rom, address);
var filtered = codeStrings.Select(cs => FilterCodeString(cs)).ToArray();
2015-03-16 04:16:12 +00:00
2015-03-22 23:55:34 +00:00
builder.Append(String.Format("[{0}]", String.Join(" ", filtered)));
2015-03-16 04:16:12 +00:00
2015-03-25 02:02:27 +00:00
if (newLines && code.IsEnd && !suppressNextEnd)
2015-03-22 23:55:34 +00:00
{
builder.AppendLine();
}
2015-03-16 04:16:12 +00:00
}
address += code.ComputeLength(rom, address);
/*if (newLines && code.IsEnd && !suppressNextEnd)
2015-03-16 18:44:47 +00:00
{
2015-03-16 18:47:33 +00:00
builder.Append("(" + address.ToString("X") + ")");
}*/
2015-03-16 18:44:47 +00:00
2015-03-16 04:16:12 +00:00
if (readUntilEnd && code.IsEnd)
ended = true;
2015-03-25 02:02:27 +00:00
if (code.IsEnd)
{
suppressNextEnd = false;
}
else if (code.SuppressNextEnd == true)
{
suppressNextEnd = true;
}
2015-03-16 04:16:12 +00:00
}
else
{
string str = GetChar(rom, address++);
2017-03-19 22:27:24 +00:00
builder.Append(str);
2015-03-16 04:16:12 +00:00
}
if (!readUntilEnd && address >= endAddress)
ended = true;
}
return builder.ToString();
}
public string DecompileString(byte[] rom, int address, bool newLines)
{
return DecompileRange(rom, address, -1, newLines);
}
public string ReadFFString(byte[] rom, int address)
{
var builder = new StringBuilder();
bool ended = false;
while (!ended)
{
if (rom[address] == 0 && rom[address + 1] == 0xFF)
{
2015-03-22 23:55:34 +00:00
builder.Append("[00 FF]");
2015-03-16 04:16:12 +00:00
ended = true;
address += 2;
}
else if (rom[address] != 0xFF)
{
builder.Append(GetChar(rom, address++));
2015-03-16 04:16:12 +00:00
}
else
{
address++;
}
}
return builder.ToString();
}
public string GetChar(byte[] rom, int address)
2015-03-16 04:16:12 +00:00
{
byte value = rom[address];
2015-03-22 23:55:34 +00:00
if (!CharLookup.ContainsKey(value))
2015-03-16 04:16:12 +00:00
{
// Invalid
throw new Exception("Invalid character 0x" + value.ToString("X2") + " at address 0x" + address.ToString("X7"));
2015-03-16 04:16:12 +00:00
}
2015-03-22 23:55:34 +00:00
return CharLookup[value];
2015-03-16 04:16:12 +00:00
}
}
}