mirror of
https://github.com/Hunter-Raff/e-ReaderCardCreator.git
synced 2025-12-14 10:00:33 +00:00
283 lines
9.7 KiB
C#
283 lines
9.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using AC_e_Reader_Card_Creator.References;
|
|
|
|
namespace AC_e_Reader_Card_Creator.Decompression.Functions
|
|
{
|
|
internal class Compress
|
|
{
|
|
public static void DECtoVPK(string greeting, string body, string closing, string stationery, string sender, string gift)
|
|
{
|
|
string new_greeting = greeting;
|
|
int player_index = greeting.IndexOf("<Player>");
|
|
|
|
if(player_index != -1)
|
|
{
|
|
new_greeting = string.Concat(greeting.AsSpan(0, player_index), greeting.AsSpan(player_index + 8));
|
|
}
|
|
|
|
new_greeting = ACAsciiToBytes(new_greeting.PadRight(24, ' '));
|
|
|
|
string new_body = body.Replace('\r'.ToString(), "").PadRight(192, ' ');
|
|
new_body = ACAsciiToBytes(new_body);
|
|
|
|
// should only be true if letter uses special characters
|
|
if(new_body.Length < 384)
|
|
{
|
|
while(new_body.Length < 384)
|
|
{
|
|
new_body += "20";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// failsafe -- if programmed correctly, this should never run
|
|
new_body = new_body[..384];
|
|
}
|
|
|
|
string new_closing = closing.PadRight(31, ' ');
|
|
new_closing = ACAsciiToBytes(new_closing);
|
|
|
|
Dictionary<string, string> StationeryMappings = ReadMappings(Common.STATIONERY_LIST);
|
|
string new_stationery = StationeryMappings[stationery][2..];
|
|
|
|
Dictionary<string, string> SenderMappings = ReadMappings(Common.SENDER_LIST);
|
|
string new_sender = SenderMappings[sender][2..];
|
|
|
|
string final = player_index.ToString("X2") + Random2ByteHex();
|
|
|
|
string bytesToWrite = new_greeting + new_body + new_closing + new_stationery + gift + new_sender + final;
|
|
|
|
byte[] body_bytes = HexStringToByteArray(bytesToWrite);
|
|
string filePath = Common.DECOMPRESSED_GCN;
|
|
File.WriteAllBytes(filePath, body_bytes);
|
|
|
|
ProcessStartInfo dec_to_vpk = new()
|
|
{
|
|
FileName = Common.NEVPK,
|
|
Arguments = Common.NEVPK_ARGS_COMP(Common.DECOMPRESSED_GCN),
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
CreateNoWindow = true
|
|
};
|
|
using (Process process = Process.Start(dec_to_vpk)) { process.WaitForExit(); }
|
|
|
|
FixVPKChecksums();
|
|
}
|
|
|
|
private static string Random2ByteHex()
|
|
{
|
|
Random random = new();
|
|
int randomNumber = random.Next(0, 130);
|
|
return randomNumber.ToString("X4");
|
|
}
|
|
|
|
public static void VPKtoBIN()
|
|
{
|
|
if (File.Exists(Common.COMPRESSED_BIN))
|
|
{
|
|
File.Delete(Common.COMPRESSED_BIN);
|
|
}
|
|
|
|
string[] VPKfiles = [Common.VPK_HEADER, Common.VPK_GBA, Common.VPK_GCN];
|
|
|
|
using (FileStream NewBIN = new(Common.COMPRESSED_BIN, FileMode.CreateNew))
|
|
{
|
|
foreach (var sourceFile in VPKfiles)
|
|
{
|
|
byte[] fileContent = File.ReadAllBytes(sourceFile);
|
|
NewBIN.Write(fileContent, 0, fileContent.Length);
|
|
}
|
|
|
|
long currentBINSize = NewBIN.Length;
|
|
long paddingSize = 2112 - currentBINSize;
|
|
|
|
if (paddingSize > 0)
|
|
{
|
|
NewBIN.Seek(0, SeekOrigin.End);
|
|
|
|
// creating a padding buffer of 0x00 bytes to fill 2112 bytes
|
|
byte[] padding = new byte[paddingSize];
|
|
NewBIN.Write(padding, 0, padding.Length);
|
|
}
|
|
}
|
|
|
|
ProcessStartInfo fix_header_checksums = new(Common.HEADERFIX, $"\"{Common.COMPRESSED_BIN}\"")
|
|
{
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
CreateNoWindow = true
|
|
};
|
|
using Process process = Process.Start(fix_header_checksums);
|
|
process.WaitForExit();
|
|
}
|
|
|
|
public static void BINtoRAW(bool custom)
|
|
{
|
|
if (custom)
|
|
{
|
|
SaveFileDialog saveRAWFile = new()
|
|
{
|
|
Filter = "RAW files (*.raw)|*.raw",
|
|
Title = "Save .RAW",
|
|
FileName = "My-Custom-eCard.raw"
|
|
};
|
|
if (saveRAWFile.ShowDialog() == DialogResult.OK)
|
|
{
|
|
ProcessStartInfo bin_to_raw = new()
|
|
{
|
|
FileName = Common.NEDCENC,
|
|
Arguments = Common.NEDCENC_ARGS_COMP(saveRAWFile.FileName),
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
CreateNoWindow = true
|
|
};
|
|
using Process process = Process.Start(bin_to_raw);
|
|
process.WaitForExit();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProcessStartInfo bin_to_raw = new()
|
|
{
|
|
FileName = Common.NEDCENC,
|
|
Arguments = Common.NEDCENC_ARGS_COMP(Common.RAW_ECARD),
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
CreateNoWindow = true
|
|
};
|
|
using Process process = Process.Start(bin_to_raw);
|
|
process.WaitForExit();
|
|
}
|
|
}
|
|
|
|
static Dictionary<string, string> ReadMappings(string filePath)
|
|
{
|
|
var map = new Dictionary<string, string>();
|
|
foreach (var line in File.ReadAllLines(filePath))
|
|
{
|
|
var parts = line.Split(',');
|
|
if (parts.Length >= 2)
|
|
{
|
|
string hexKey = parts[0].Trim();
|
|
string value = parts[1].Trim().Trim('\'');
|
|
map[value] = hexKey;
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
|
|
private static void FixVPKChecksums()
|
|
{
|
|
try
|
|
{
|
|
FileInfo fileInfo = new(Common.VPK_GCN);
|
|
long GCN_VPK_Length = 0;
|
|
|
|
if (fileInfo.Exists)
|
|
{
|
|
GCN_VPK_Length = fileInfo.Length;
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("ERROR: Failed to fetch GCN VPK");
|
|
return;
|
|
}
|
|
|
|
string GCN_VPK_Hex_Length = GCN_VPK_Length.ToString("X").PadLeft(4, '0');
|
|
|
|
if (!File.Exists(Common.VPK_GBA))
|
|
{
|
|
MessageBox.Show("ERROR: Failed to fetch GBA VPK");
|
|
return;
|
|
}
|
|
byte[] fileContents = File.ReadAllBytes(Common.VPK_GBA);
|
|
|
|
if (fileContents.Length < 2)
|
|
{
|
|
MessageBox.Show("ERROR: GBA VPK exists, but is smaller in size than expected");
|
|
return;
|
|
}
|
|
|
|
byte[] GCN_FileSize_Checksum = HexStringToByteArray(GCN_VPK_Hex_Length);
|
|
|
|
fileContents[^2] = GCN_FileSize_Checksum[1];
|
|
fileContents[^1] = GCN_FileSize_Checksum[0];
|
|
|
|
File.WriteAllBytes(Common.VPK_GBA, fileContents);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"An error occurred: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public static string ACAsciiToBytes(string input)
|
|
{
|
|
Dictionary<string, string> map = ReadMappings(Common.SP_CHAR_LIST);
|
|
var sb = new StringBuilder();
|
|
var textElementEnumerator = StringInfo.GetTextElementEnumerator(input);
|
|
|
|
// a bit hacky and inefficient, but should work
|
|
while (textElementEnumerator.MoveNext())
|
|
{
|
|
string textElement = textElementEnumerator.GetTextElement();
|
|
if (textElement == "\n")
|
|
{
|
|
sb.Append("CD");
|
|
}
|
|
else if (textElement.Length == 1)
|
|
{
|
|
if (map.TryGetValue(textElement, out string value))
|
|
{
|
|
sb.Append(value[2..]);
|
|
}
|
|
else
|
|
{
|
|
char c = textElement[0];
|
|
if ((byte)c >= 32 && (byte)c <= 127)
|
|
{
|
|
byte char_byte = (byte)c;
|
|
sb.Append(char_byte.ToString("X2"));
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("An unexpected error occurred!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
}
|
|
else if (map.TryGetValue(textElement, out string value))
|
|
{
|
|
sb.Append(value.AsSpan(2));
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("Test!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
return sb.ToString().Trim();
|
|
}
|
|
|
|
static byte[] HexStringToByteArray(string hex)
|
|
{
|
|
int numberChars = hex.Length;
|
|
byte[] bytes = new byte[numberChars / 2];
|
|
for (int i = 0; i < numberChars; i += 2)
|
|
{
|
|
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|