Files
sceWork/Program.cs

536 lines
21 KiB
C#
Raw Permalink Normal View History

2021-02-06 17:43:14 -05:00
using StreamFAdd;
using System;
using System.Collections.Generic;
using System.Globalization;
2021-02-06 17:43:14 -05:00
using System.IO;
using System.Linq;
using System.Text;
namespace sceWork
{
internal class Program
{
public static tableModule jpcodes;
public static tableModule codes;
public static Encoding SJIS = Encoding.GetEncoding(932);
public static String altPath;
private static bool useSJIS = false;
private static bool useAltPath = false;
private static bool doDeduplication = false;
private static bool dumpRaw = false;
2021-03-02 15:16:41 -05:00
private static bool dumpCount = false;
private static bool flag1 = false;
private static bool flag2 = false;
public static bool verbose = false;
2021-02-06 17:43:14 -05:00
private static void Main(string[] args)
{
2021-04-17 18:05:58 -04:00
Console.WriteLine("TOD1RSCE sceWork v0.9 - Cross-Platform");
string exeDir = Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
exeDir = new Uri(exeDir).LocalPath;
if (File.Exists(Path.Combine(exeDir, "jpcodes.txt")))
jpcodes = new tableModule(Path.Combine(exeDir, "jpcodes.txt"));
if (File.Exists(Path.Combine(exeDir, "codes.txt")))
codes = new tableModule(Path.Combine(exeDir, "codes.txt"), true);
if (args.Length == 0)
2021-02-06 17:43:14 -05:00
{
Console.WriteLine("Generously donated by Temple of Tales Translations team");
Console.WriteLine("http://temple-tales.ru/translations.html\n");
Console.WriteLine("Usage:");
2021-03-07 17:21:39 -05:00
Console.WriteLine(" extract: .exe -e *.tod1rsce");
Console.WriteLine(" extract: .exe -e *.tod1rsce4");
Console.WriteLine(" extract: .exe -e *.rsce");
Console.WriteLine(" extract: .exe -e <dir>");
Console.WriteLine(" repack : .exe -r *.tod1rsce");
Console.WriteLine(" repack : .exe -r *.tod1rsce4");
Console.WriteLine(" repack : .exe -r *.rsce");
Console.WriteLine(" repack : .exe -r <dir>");
Console.WriteLine("Add params:");
Console.WriteLine(" -i : Specify a diferent input file");
Console.WriteLine(" -v : Verbose failed string output");
Console.WriteLine(" -as <count> : Add <count> bytes to start file");
Console.WriteLine(" -ae : Seek file to 16 bytes");
2021-03-02 15:16:41 -05:00
Console.WriteLine(" -sjis : Use CP-932 (SHIFT-JIS) encoding");
Console.WriteLine(" -dedup : deduplicate strings on insertion");
Console.WriteLine(" -count : Dump byte count (debug)");
2021-03-02 15:16:41 -05:00
Console.WriteLine(" -raw : Dump/insert raw bytes ignoring JPCODES and CODES");
//Console.ReadKey();
Environment.Exit(0);
2021-02-06 17:43:14 -05:00
}
ParseArgs(args);
string str = args[0];
//Do extraction
if (str == "-e")
{
if (Path.GetExtension(args[1]) == ".rsce" || Path.GetExtension(args[1]) == ".tod1rsce" || Path.GetExtension(args[1]) == ".tod1rsce4")
{
if (jpcodes == null)
{
MiscUtils.Warn("No JPCODES.txt file! Dumping raw bytes...");
}
Extract(args[1]);
}
else if (Directory.Exists(args[1]))
{
foreach (string fileName in ((IEnumerable<string>)Directory.GetFiles(args[1], "*.*", SearchOption.AllDirectories)).Where<string>((Func<string, bool>)(s => s.EndsWith(".rsce") || s.EndsWith(".tod1rsce") || s.EndsWith(".tod1rsce4"))).ToArray<string>())
Extract(fileName);
}
}
//Do insertion
if (str == "-r")
{
if (Path.GetExtension(args[1]) == ".rsce" || Path.GetExtension(args[1]) == ".tod1rsce" || Path.GetExtension(args[1]) == ".tod1rsce4")
{
if (jpcodes == null)
{
MiscUtils.Warn("No JPCODES.txt file! Assuming dump is raw...");
}
Repack(args[1]);
AddBytes(args[1], args);
}
else if (Directory.Exists(args[1]))
{
string[] array = ((IEnumerable<string>)Directory.GetFiles(args[1], "*.*", SearchOption.AllDirectories)).Where<string>((Func<string, bool>)(s => s.EndsWith(".rsce") || s.EndsWith(".tod1rsce") || s.EndsWith(".tod1rsce4"))).ToArray<string>();
for (int index = 0; index < array.Length; ++index)
{
Repack(array[index]);
AddBytes(array[index], args);
}
}
}
Console.WriteLine("Complete!");
//Console.ReadKey();
2021-02-06 17:43:14 -05:00
}
private static void ParseArgs(string[] args)
2021-02-06 17:43:14 -05:00
{
for (int index = 0; index < args.Length; ++index)
{
try
{
if (args[index] == "-i")
{
useAltPath = true;
if (!File.Exists(Path.GetFullPath(args[index + 1])))
{
MiscUtils.Die("Error. The file of the -i parameter does not exist.");
}
altPath = Path.GetFullPath(args[index + 1]);
MiscUtils.Info("Using input file: \"" + altPath + "\"");
index++;
}
if (args[index] == "-v")
{
verbose = true;
MiscUtils.Info("verbose mode active");
}
if (args[index] == "-sjis")
{
useSJIS = true;
MiscUtils.Info("using CP-932 (SHIFT-JIS) for this operation.");
}
2021-03-02 15:16:41 -05:00
if (args[index] == "-count")
{
dumpCount = true;
MiscUtils.Info("dumping debug byte counts to file.");
2021-03-02 15:16:41 -05:00
}
if (args[index] == "-dedup")
{
doDeduplication = true;
MiscUtils.Info("string deduplication is active for this operation.");
}
if (args[index] == "-raw")
{
dumpRaw = true;
MiscUtils.Info("Ignoring JPCODES and CODES for this operation.");
}
2021-02-06 17:43:14 -05:00
if (args[index] == "-as")
{
flag1 = true;
MiscUtils.Info("Activate add bytes to start.");
if (!int.TryParse(args[index + 1], out _))
{
MiscUtils.Die("Error. The value of the -as parameter is not a number.");
}
index++;
2021-02-06 17:43:14 -05:00
}
if (args[index] == "-ae")
{
flag2 = true;
MiscUtils.Info("Activate add %16 to end.");
2021-02-06 17:43:14 -05:00
}
}
catch (Exception)
2021-02-06 17:43:14 -05:00
{
MiscUtils.Die("Parameter reference error, perhaps a parameter was entered, but its value was not entered.");
2021-02-06 17:43:14 -05:00
}
}
}
private static void AddBytes(string fileName, string[] args)
{
int result = 0;
Console.ForegroundColor = ConsoleColor.Red;
for (int index = 0; index < args.Length; ++index)
{
if (args[index] == "-as")
{
int.TryParse(args[index + 1], out result);
}
}
2021-02-06 17:43:14 -05:00
Console.ForegroundColor = ConsoleColor.White;
StreamFunctionAdd streamFunctionAdd1 = new StreamFunctionAdd();
StreamFunctionAdd streamFunctionAdd2 = new StreamFunctionAdd(fileName);
if (flag2)
{
streamFunctionAdd2.PositionStream = streamFunctionAdd2.LengthStream;
streamFunctionAdd2.SeekValueWrite(16U);
}
if (!flag1)
return;
StreamFunctionAdd destination = new StreamFunctionAdd();
for (int index = 0; index < result; ++index)
destination.WriteByte((byte)0);
streamFunctionAdd2.PositionStream = 0L;
streamFunctionAdd2.CopyPartTo(destination, (int)streamFunctionAdd2.LengthStream);
streamFunctionAdd2.Dispose();
destination.SaveToFile(fileName);
}
private static void Extract(string fileName)
{
sceModule sceModule = new sceModule(fileName);
if (!sceModule.isHaveText())
return;
string path = !(Path.GetDirectoryName(fileName) != "") ? Environment.CurrentDirectory + "\\" + Path.GetFileNameWithoutExtension(fileName) + ".txt" : Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + ".txt";
Console.WriteLine(string.Format("Extracting {0}...", Path.GetFileName(fileName)));
if (jpcodes == null || dumpRaw)
{
ExtractRaw(fileName, sceModule);
return;
}
if (dumpCount)
{
ExtractCount(fileName, sceModule);
return;
}
if (codes == null)
MiscUtils.Warn("No CODES.txt file! Special sequences will be ignored, output can get messy!");
2021-02-06 17:43:14 -05:00
List<string> stringList = new List<string>();
2021-03-02 15:16:41 -05:00
for (int idx = 0; idx < sceModule.Count; ++idx)
2021-02-06 17:43:14 -05:00
{
string str = sceModule.GetStringBlock(idx);
if (codes != null)
str = codes.ConvertNativeToTags(str);
if (jpcodes != null)
str = jpcodes.ConvertAtoB(str);
stringList.Add(HexToAnsi(str));
2021-02-06 17:43:14 -05:00
stringList.Add("[ENDBLOCK]");
}
if (useSJIS)
File.WriteAllLines(path, stringList.ToArray(), SJIS);
else
File.WriteAllLines(path, stringList.ToArray());
2021-02-06 17:43:14 -05:00
}
private static void ExtractRaw(string fileName, sceModule sceModule)
{
string path;
if (Path.GetDirectoryName(fileName) == "")
{
path = Environment.CurrentDirectory + "\\" + Path.GetFileNameWithoutExtension(fileName) + "_raw.txt";
}
else
{
path = Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + "_raw.txt";
}
List<byte> dump = new List<byte>();
for (int idx = 0; idx < sceModule.Count; ++idx)
{
dump.AddRange(sceModule.GetBlock(idx));
dump.AddRange(Encoding.ASCII.GetBytes("\r\n[ENDBLOCK]\r\n"));
}
File.WriteAllBytes(path, dump.ToArray());
return;
}
private static void ExtractCount(string fileName, sceModule sceModule)
{
string path;
if (Path.GetDirectoryName(fileName) == "")
{
path = Environment.CurrentDirectory + "\\" + Path.GetFileNameWithoutExtension(fileName) + "_count.txt";
}
else
{
path = Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + "_count.txt";
}
List<string> byteInfo = new List<string>();
int total = 0;
bool switch1 = true;
for (int idx = 0; idx < sceModule.Count; ++idx)
{
total += sceModule.GetBlock(idx).Length;
if (total > 0xFFF && switch1)
{
byteInfo.Add("-----------CUT POINT-----------------------");
byteInfo.Add("| length average: " + (total / idx + 1));
byteInfo.Add("-----------CUT POINT-----------------------");
switch1 = false;
}
byteInfo.Add(string.Format("Block: {0:D3},", idx)
+ string.Format(" Ptr: 0x{0:X6}", sceModule.Header.fileStrings[idx].myOffset)
+ string.Format(" ({0:D}),", (int)sceModule.Header.fileStrings[idx].typeOffset)
+ string.Format(" Text: 0x{0:X6}", sceModule.Header.fileStrings[idx].offset)
+ string.Format(" | Line length: {0:D3}, ", sceModule.GetBlock(idx).Length)
+ string.Format("total length: {0:D4}", total));
}
File.WriteAllLines(path, byteInfo.ToArray());
return;
}
2021-02-06 17:43:14 -05:00
private static void Repack(string fileName)
{
sceModule sceModule = new sceModule(fileName);
//check if rsce has text beforehand
2021-02-06 17:43:14 -05:00
if (!sceModule.isHaveText())
return;
string path;
if (useAltPath)
path = altPath;
else
{
if (Path.GetDirectoryName(fileName) == "")
path = Environment.CurrentDirectory + "\\" + Path.GetFileNameWithoutExtension(fileName) + ".txt";
else
path = Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + ".txt";
}
2021-02-06 17:43:14 -05:00
if (!File.Exists(path))
MiscUtils.Die("The file \"" + Path.GetFileName(path) + "\" does not exist!");
//Echo!
Console.WriteLine(string.Format("Repacking {0}...", Path.GetFileName(fileName)));
if (jpcodes == null || dumpRaw)
{
RepackRaw(path, sceModule);
return;
}
//Convert UTF-8 to SJIS, as it's easier to detect kanjis in SJIS
byte[] temp;
if (!useSJIS)
temp = Encoding.Convert(Encoding.UTF8, SJIS, File.ReadAllBytes(path));
else
temp = File.ReadAllBytes(path);
string[] stringSeparators = new string[] { "\r\n" };
string[] strArray = SJIS.GetString(temp).Split(stringSeparators, StringSplitOptions.None);
//Can't ignore empty lines with the split (some lines might be blank in the source file)
//but the last line can't be blank, so handle that here
if (strArray[strArray.Length - 1].Equals(string.Empty))
{
Array.Resize(ref strArray, strArray.Length - 1);
}
2021-02-06 17:43:14 -05:00
List<string> stringList = new List<string>();
List<string> plainStringList = new List<string>();
List<int> lineNumberList = new List<int>();
int lineNumber = 0;
int blockLine = 0;
2021-02-06 17:43:14 -05:00
string str = "";
for (int index = 0; index < strArray.Length; ++index)
{
if (strArray[index].StartsWith("//"))
continue;
if (strArray[index].StartsWith("[ENDBLOCK]"))
2021-02-06 17:43:14 -05:00
{
lineNumberList.Add(lineNumber - blockLine);
blockLine = 0;
2021-02-06 17:43:14 -05:00
stringList.Add(str);
plainStringList.Add(str.Replace("\r\n", "\\r\\n"));
2021-02-06 17:43:14 -05:00
str = "";
}
else
{
if (strArray[index + 1].StartsWith("[ENDBLOCK]"))
{
str = str + strArray[index];
}
else
{
str = str + strArray[index] + "\r\n";
blockLine++;
}
}
lineNumber++;
2021-02-06 17:43:14 -05:00
}
//check if same ammount of lines are present
if (sceModule.Header.fileStrings.Count != stringList.Count)
{
MiscUtils.Warn("Different amount of strings in the file!");
MiscUtils.Warn("expected "
+ sceModule.Header.fileStrings.Count + " but got "
+ stringList.Count);
MiscUtils.Warn("Packing anyway, but expect errors!");
Console.WriteLine();
}
2021-02-06 17:43:14 -05:00
for (int index = 0; index < stringList.Count; ++index)
stringList[index] = AnsiToHex(stringList[index]);
if (jpcodes != null)
2021-02-06 17:43:14 -05:00
{
for (int index = 0; index < stringList.Count; ++index)
stringList[index] = jpcodes.ConvertBtoA(stringList[index]);
2021-02-06 17:43:14 -05:00
}
if (codes != null)
2021-02-06 17:43:14 -05:00
{
for (int index = 0; index < stringList.Count; ++index)
stringList[index] = codes.ConvertTagsToNative(stringList[index]);
2021-02-06 17:43:14 -05:00
}
else
{
MiscUtils.Warn("No CODES.txt file! If the file has replaced tags they will be inserted verbatim!");
}
int realLine = 0;
int skippedLine = 0;
2021-02-06 17:43:14 -05:00
for (int index = 0; index < stringList.Count; ++index)
{
realLine++;
while (stringList[index].StartsWith(AnsiToHex("<IGNORE>")))
{
if (verbose)
MiscUtils.Info("Ignoring block " + realLine + " (around line " + lineNumberList[index] + ")...");
lineNumberList.RemoveAt(index);
plainStringList.RemoveAt(index);
sceModule.Header.fileStrings.RemoveAt(index);
stringList.RemoveAt(index);
realLine++;
skippedLine++;
}
sceModule.SetBlock(index, HexToArrayByte(stringList[index]), plainStringList, lineNumberList);
}
MiscUtils.Info("Ignored " + skippedLine + " blocks");
Console.WriteLine();
sceModule.Save(doDeduplication);
2021-02-06 17:43:14 -05:00
sceModule.Dispose();
}
private static void RepackRaw(string path, sceModule sceModule)
{
byte[] dump = File.ReadAllBytes(path);
string hexStringDump = BitConverter.ToString(dump).Replace("-", string.Empty);
2021-02-06 17:43:14 -05:00
string[] hexDump = hexStringDump.Split(new[] { AnsiToHex("\r\n[ENDBLOCK]\r\n") }, StringSplitOptions.None);
if (hexDump[hexDump.Length - 1].Equals(string.Empty))
{
Array.Resize(ref hexDump, hexDump.Length - 1);
}
for (int index = 0; index < hexDump.Length; ++index)
sceModule.SetBlock(index, HexToArrayByte(hexDump[index]));
sceModule.Save();
sceModule.Dispose();
return;
}
2021-02-06 17:43:14 -05:00
private static byte[] HexToArrayByte(string str)
{
List<byte> byteList = new List<byte>();
for (int index = 0; index < str.Length; index += 2)
{
byte num = (byte)(((uint)Program.HexToByte(str[index]) << 4) + (uint)Program.HexToByte(str[index + 1]));
byteList.Add(num);
}
return byteList.ToArray();
}
private static byte HexToByte(char s)
{
switch (s)
{
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'A':
return 10;
case 'B':
return 11;
case 'C':
return 12;
case 'D':
return 13;
case 'E':
return 14;
case 'F':
return 15;
default:
return 0;
}
}
private static string HexToAnsi(string str)
{
byte[] temp = Encoding.Convert(Encoding.GetEncoding(932), Encoding.UTF8, Program.HexToArrayByte(str));
return Encoding.UTF8.GetString(temp);
}
2021-02-06 17:43:14 -05:00
private static string AnsiToHex(string str)
{
string str1 = "";
byte[] byteArr = Encoding.GetEncoding(932).GetBytes(str);
for (int index = 0; index < byteArr.Length; ++index)
str1 += System.BitConverter.ToString(byteArr, index, 1).Replace("-", string.Empty);
2021-02-06 17:43:14 -05:00
return str1;
}
private static byte GetAnsiByte(char chr) => Encoding.GetEncoding(932).GetBytes(chr.ToString())[0];
2021-02-06 17:43:14 -05:00
private static string GetAnsi(byte[] data) => Encoding.GetEncoding(932).GetString(data, 0, data.Length);
2021-02-06 17:43:14 -05:00
}
}