SharpCreditsCrediter/ROMFile.cs

200 lines
5.3 KiB
C#
Raw Normal View History

2023-10-27 20:36:27 +00:00
using System.Text;
namespace SharpCreditsCrediter
{
2023-10-27 21:47:09 +00:00
internal class ROMFile
{
private FileStream? romFile;
2023-10-27 20:36:27 +00:00
const long ZM_credits_start = 0x54C10C;
const long ZM_credits_end = 0x54E2A9;
const long MF_credits_start = 0x74B0B0;
const long MF_credits_end = 0x74DC25;
private bool isZM = true;
2023-10-27 21:47:09 +00:00
private readonly Dictionary<char, int> textToIntTable = new Dictionary<char, int>() {
{ ' ', 0x20 }, { 'A', 0x41 }, { 'B', 0x42 }, { 'C', 0x43 }, { 'D', 0x44 }, { 'E', 0x45 }, { 'F', 0x46 }, { 'G', 0x47 },
{ 'H', 0x48 }, { 'I', 0x49 }, { 'J', 0x4A }, { 'K', 0x4B }, { 'L', 0x4C }, { 'M', 0x4D }, { 'N', 0x4E }, { 'O', 0x4F },
{ 'P', 0x50 }, { 'Q', 0x51 }, { 'R', 0x52 }, { 'S', 0x53 }, { 'T', 0x54 }, { 'U', 0x55 }, { 'V', 0x56 }, { 'W', 0x57 },
{ 'X', 0x58 }, { 'Y', 0x59 }, { 'Z', 0x5A }, { 'a', 0x61 }, { 'b', 0x62 }, { 'c', 0x63 }, { 'd', 0x64 }, { 'e', 0x65 },
{ 'f', 0x66 }, { 'g', 0x67 }, { 'h', 0x68 }, { 'i', 0x69 }, { 'j', 0x6A }, { 'k', 0x6B }, { 'l', 0x6C }, { 'm', 0x6D },
{ 'n', 0x6E }, { 'o', 0x6F }, { 'p', 0x70 }, { 'q', 0x71 }, { 'r', 0x72 }, { 's', 0x73 }, { 't', 0x74 }, { 'u', 0x75 },
{ 'v', 0x76 }, { 'w', 0x77 }, { 'x', 0x78 }, { 'y', 0x79 }, { 'z', 0x7A }, { '&', 0x26 }
};
private readonly Dictionary<int, string> intToTextTable = new Dictionary<int, string>() {
{ 0x20, " " }, { 0x41, "A" }, { 0x42, "B" }, { 0x43, "C" }, { 0x44, "D" }, { 0x45, "E" }, { 0x46, "F" }, { 0x47, "G" },
{ 0x48, "H" }, { 0x49, "I" }, { 0x4A, "J" }, { 0x4B, "K" }, { 0x4C, "L" }, { 0x4D, "M" }, { 0x4E, "N" }, { 0x4F, "O" },
{ 0x50, "P" }, { 0x51, "Q" }, { 0x52, "R" }, { 0x53, "S" }, { 0x54, "T" }, { 0x55, "U" }, { 0x56, "V" }, { 0x57, "W" },
{ 0x58, "X" }, { 0x59, "Y" }, { 0x5A, "Z" }, { 0x61, "a" }, { 0x62, "b" }, { 0x63, "c" }, { 0x64, "d" }, { 0x65, "e" },
{ 0x66, "f" }, { 0x67, "g" }, { 0x68, "h" }, { 0x69, "i" }, { 0x6A, "j" }, { 0x6B, "k" }, { 0x6C, "l" }, { 0x6D, "m" },
{ 0x6E, "n" }, { 0x6F, "o" }, { 0x70, "p" }, { 0x71, "q" }, { 0x72, "r" }, { 0x73, "s" }, { 0x74, "t" }, { 0x75, "u" },
2023-10-27 20:36:27 +00:00
{ 0x76, "v" }, { 0x77, "w" }, { 0x78, "x" }, { 0x79, "y" }, { 0x7A, "z" }, { 0x26, "&" }
};
private string intToText(int value)
{
2023-10-27 21:47:09 +00:00
try
{
2023-10-27 20:36:27 +00:00
return intToTextTable[value];
2023-10-27 21:47:09 +00:00
}
catch (Exception)
2023-10-27 20:36:27 +00:00
{
return String.Format("{0:X2}", Convert.ToInt32(value));
}
}
2023-10-27 21:47:09 +00:00
private int textToInt(char value)
{
try
{
return textToIntTable[value];
}
catch (Exception)
{
return 0;
}
}
public ROMFile(String pathToROM)
{
2023-10-27 20:36:27 +00:00
this.changeFile(pathToROM);
2023-10-27 21:47:09 +00:00
}
2023-10-27 20:36:27 +00:00
private void probeGame()
{
2023-10-27 21:47:09 +00:00
if (this.isLoaded())
2023-10-27 20:36:27 +00:00
{
#pragma warning disable CS8602 // isLoaded checks already if romFile is null or not
2023-10-27 21:47:09 +00:00
byte[] gameCodeBuf = new byte[4];
2023-10-27 20:36:27 +00:00
romFile.Position = 0xAC;
if (romFile.Read(gameCodeBuf, 0, 4) == 4)
{
string gameCode = Encoding.ASCII.GetString(gameCodeBuf);
2023-10-27 21:47:09 +00:00
if (gameCode == "AMTE")
2023-10-27 20:36:27 +00:00
{
this.isZM = false;
2023-10-27 21:47:09 +00:00
}
else
2023-10-27 20:36:27 +00:00
{
this.isZM = true;
}
}
#pragma warning restore CS8602
2023-10-27 21:47:09 +00:00
}
}
2023-10-27 20:36:27 +00:00
public void changeFile(String pathToROM)
{
if (this.isLoaded()) this.Dispose();
2023-10-27 21:47:09 +00:00
romFile = File.Open(pathToROM, FileMode.Open);
2023-10-27 20:36:27 +00:00
this.probeGame();
2023-10-27 21:47:09 +00:00
}
2023-10-27 20:36:27 +00:00
public bool isLoaded()
{
return romFile != null;
}
public void setisZM(bool isZM)
{
this.isZM = isZM;
}
2023-10-27 21:47:09 +00:00
public bool getisZM()
{
return isZM;
}
2023-10-27 20:36:27 +00:00
2023-10-27 21:47:09 +00:00
public void Dispose()
2023-10-27 20:36:27 +00:00
{
romFile?.Dispose();
}
public String getCredits()
{
string credits = "";
if (romFile != null)
{
long credits_start = isZM ? ZM_credits_start : MF_credits_start;
long credits_end = isZM ? ZM_credits_end : MF_credits_end;
2023-10-27 21:47:09 +00:00
romFile.Position = credits_start;
2023-10-27 20:36:27 +00:00
bool end_reached = false;
while (romFile.Position < credits_end && !end_reached)
{
int curChar = romFile.ReadByte();
2023-10-27 21:47:09 +00:00
if (curChar == 6) end_reached = true;
2023-10-27 20:36:27 +00:00
2023-10-27 21:47:09 +00:00
credits += intToText(curChar) + " ";
2023-10-27 20:36:27 +00:00
2023-10-27 21:47:09 +00:00
for (int i = 0; i < 35; i++)
2023-10-27 20:36:27 +00:00
{
2023-10-27 21:47:09 +00:00
curChar = romFile.ReadByte();
if (curChar != 0)
2023-10-27 20:36:27 +00:00
credits += intToText(curChar);
}
credits += Environment.NewLine;
2023-10-27 21:47:09 +00:00
}
}
2023-10-27 20:36:27 +00:00
return credits;
}
public bool writeCredits(StreamReader credits)
{
try
{
if (romFile != null && credits != null)
{
long credits_start = isZM ? ZM_credits_start : MF_credits_start;
romFile.Position = credits_start;
while (!credits.EndOfStream)
{
var currentLine = credits.ReadLine();
if (currentLine != null)
{
2023-10-27 21:47:09 +00:00
if (currentLine.Length > 38)
{
2023-10-27 20:36:27 +00:00
currentLine = currentLine[..38];
}
// get line marker byte
int markerByte = Convert.ToInt32(currentLine[0..2], 16);
romFile.WriteByte((byte)markerByte);
if (markerByte == 6) break;
if (currentLine.Length > 3)
{
byte[] actualText = Encoding.ASCII.GetBytes(currentLine[3..]);
List<byte> textBytes = new List<byte>();
foreach (byte b in actualText)
textBytes.Add((byte)textToInt((char)b));
foreach (byte c in textBytes)
{
romFile.WriteByte(c);
}
2023-10-27 22:24:20 +00:00
} else {
romFile.WriteByte((byte)textToInt(' '));
2023-10-27 20:36:27 +00:00
}
for (int i = 0; i < 38 - currentLine.Length; i++) romFile.WriteByte(0);
}
}
romFile.Flush();
2023-10-27 21:47:09 +00:00
2023-10-27 20:36:27 +00:00
return true;
}
return false;
2023-10-27 21:47:09 +00:00
}
catch (Exception)
2023-10-27 20:36:27 +00:00
{
2023-10-27 21:47:09 +00:00
return false;
}
2023-10-27 20:36:27 +00:00
}
2023-10-27 21:47:09 +00:00
}
2023-10-27 20:36:27 +00:00
}