MHiRepacker/Program.cs

565 lines
20 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text;
namespace MHiRepacker
{
internal class Program
{
static string inputFile;
static bool bUnpack;
static string exceldata = "exceldata.dat";
static int mode;
static string helperStr = @"
————————————————————————
params:
[func] [inputpath] [outputpath]
func: unpack/repack
unpack: [inputpath] is input File path ,[outputpath] is output Directory path
repack: [inputpath] is input Directory path ,[outputpath] is output File path
eg.
unpack G:\exceldata.dat G:\exceldata_unpacked
repack G:\exceldata_unpacked G:\exceldata.dat
unpack G:\syokibugu.dat G:\syokibugu_unpacked
repack G:\syokibugu_unpacked G:\syokibugu
————————————————————————
";
static void PrintHelperStr()
{
Console.WriteLine(helperStr);
Console.ReadLine();
}
static void Main(string[] args)
{
string title = $"MHiRepacker Ver.1.4 By 皓月云 axibug.com";
Console.Title = title;
Console.WriteLine(title);
if (args.Length < 3)
{
PrintHelperStr();
return;
}
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding shiftencode = Encoding.GetEncoding("Shift-JIS");
string modecmd = args[0];
Console.WriteLine($"func=>{args[0].ToLower()}");
string inputpath;
string outputpath;
inputpath = args[1];
outputpath = args[2];
Console.WriteLine($"inputpath=>{inputpath}");
Console.WriteLine($"outputpath=>{outputpath}");
if (bUnpack)
{
if (!File.Exists(inputpath))
{
Console.WriteLine($"未找到文件can not found file: {inputpath}");
PrintHelperStr();
return;
}
}
else if (bUnpack)
{
if (!Directory.Exists(inputpath))
{
Console.WriteLine($"未找到文件can not found directory: {inputpath}");
PrintHelperStr();
return;
}
}
if (modecmd.ToLower() == "unpack")
{
bUnpack = true;
if (!FileHelper.LoadFile(inputpath, out byte[] inputbytes))
{
Console.WriteLine($"读取失败:{inputpath}");
PrintHelperStr();
return;
}
List<uint> SizeList = new List<uint>();
List<string> tempLog = new List<string>();
uint WorkedDataLenght = 0;
if (!TryGetheadWithCheck(inputbytes, 0, false, ref SizeList, ref tempLog, out int checkmode, ref WorkedDataLenght))
{
Console.WriteLine($"读取失败,文件以0x00起始:{inputpath}");
PrintHelperStr();
return;
}
mode = checkmode;
}
else if (modecmd.ToLower() == "repack")
{
bUnpack = false;
string[] dirs = Directory.GetDirectories(inputpath).Select(w => new DirectoryInfo(w).Name).ToArray();
if (dirs.Length == 4 &&
dirs.Contains("0000") &&
dirs.Contains("0001") &&
dirs.Contains("0002") &&
dirs.Contains("0003")
)
mode = 1;
else
mode = 0;
}
else
{
PrintHelperStr();
return;
}
//if (args.Length >= 4 && args[3].ToLower() == "mode1")
// mode = 1;
//else
// mode = 0;
Console.WriteLine($"audo mode=>mode{mode}");
bool bResult = false;
#if !DEBUG
try
{
#endif
switch (mode)
{
case 0:
if (bUnpack) bResult = Unpack_Mode0(inputpath, outputpath);
else bResult = Repack_Mode0(inputpath, outputpath);
break;
case 1:
if (bUnpack) bResult = Unpack_Mode1(inputpath, outputpath);
else bResult = Repack_Mode1(inputpath, outputpath);
break;
}
#if !DEBUG
}
catch (Exception ex)
{
Console.WriteLine("处理异常:" + ex.ToString());
}
#endif
Console.WriteLine(bResult ? "处理成功" : "处理失败");
}
static bool Unpack_Mode0(string Unpack_Input, string Unpack_Output)
{
Console.WriteLine($"开始处理{Unpack_Input}");
if (!Directory.Exists(Unpack_Output))
{
Directory.CreateDirectory(Unpack_Output);
Console.WriteLine($"创建目录{Unpack_Output}");
}
if (!FileHelper.LoadFile(Unpack_Input, out byte[] inputbytes))
{
Console.WriteLine($"读取失败");
return false;
}
return Unpack_Mode0_logic(inputbytes, 0, Unpack_Output, out uint WorkedDataLenght);
}
readonly static uint StartHead = 0x01;
readonly static byte[] StartPKHead = { 0x50, 0x4B, 0x03, 0x04, 0x14 };//PK
static bool CheckPKHead(byte[] temp, int startIdx)
{
for (int i = 0; i < StartPKHead.Length; i++)
{
startIdx++;
if (startIdx < temp.Length && StartPKHead[i] != temp[startIdx])
return false;
}
return true;
}
static bool TryGetheadWithCheck(byte[] inputbytes, uint startPos, bool skipConsoleLog, ref List<uint> SizeList, ref List<string> tempLog, out int checkmode, ref uint WorkedDataLenght)
{
if (inputbytes[0] == 0x00)
{
checkmode = default;
return false;
}
WorkedDataLenght += StartHead;
uint pos = startPos + StartHead;
//bool CheckStartEnd(byte[] temp, int startIdx)
//{
// for (int i = 0; i < StartHeadEndArr.Length; i++)
// {
// if (StartHeadEndArr[i] != temp[startIdx++])
// return true;
// }
// return false;
//}
//int idx = 0;
uint StartContentPtr = 0;
string log;
log = $"文件头读取:";
if (!skipConsoleLog) Console.WriteLine(log);
tempLog.Add(log);
//while (CheckStartEnd(inputbytes, (int)pos) && CheckStartEnd(inputbytes, (int)pos + 1))
for (int idx = 0; idx < inputbytes[0]; idx++)
{
uint size = HexHelper.bytesToUInt(inputbytes, 2, (int)pos);
SizeList.Add(size);
log = $"lenght:[{idx}]=>{size}({size.ToString("X")})| byte src: 0x{inputbytes[pos].ToString("X")} 0x{inputbytes[pos + 1].ToString("X")}";
if (!skipConsoleLog) Console.WriteLine(log);
tempLog.Add(log);
pos += 2;
WorkedDataLenght += 2;
}
log = $"读取完毕共{SizeList.Count}个";
if (!skipConsoleLog) Console.WriteLine(log);
tempLog.Add(log);
long packagelenght = WorkedDataLenght + SizeList.Sum(w => w);
checkmode = inputbytes.Length == packagelenght ? 0 : 1;
return true;
}
static bool Unpack_Mode0_logic(byte[] inputbytes, uint startPos, string Unpack_Output, out uint WorkedDataLenght)
{
WorkedDataLenght = 0;
uint StartHead = 0x01;
WorkedDataLenght += StartHead;
//byte[] StartHeadEndArr = { 0x50, 0x4B, 0x03, 0x04, 0x14 };//PK
List<string> tempLog = new List<string>();
uint pos = startPos + StartHead;
List<uint> SizeList = new List<uint>();
try
{
uint StartContentPtr = 0;
string log;
tempLog.Add("文件头读取:");
//while (CheckStartEnd(inputbytes, (int)pos) && CheckStartEnd(inputbytes, (int)pos + 1))
for (int idx = 0; idx < inputbytes[0]; idx++)
{
uint size = HexHelper.bytesToUInt(inputbytes, 2, (int)pos);
SizeList.Add(size);
log = $"lenght:[{idx}]=>{size}({size.ToString("X")})| byte src: 0x{inputbytes[pos].ToString("X")} 0x{inputbytes[pos + 1].ToString("X")}";
Console.WriteLine(log);
tempLog.Add(log);
pos += 2;
WorkedDataLenght += 2;
}
log = $"读取完毕共{SizeList.Count}个";
Console.WriteLine(log);
tempLog.Add(log);
StartContentPtr = pos;
for (int i = 0; i < SizeList.Count; i++)
{
string filename = Unpack_Output + $"\\{i.ToString().PadLeft(3, '0')}.zip";
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
fs.Write(inputbytes, (int)StartContentPtr, (int)SizeList[i]);
}
StartContentPtr += SizeList[i];
WorkedDataLenght += SizeList[i];
log = $"写入{filename}";
Console.WriteLine(log);
tempLog.Add(log);
}
log = $"Unpack完毕共{SizeList.Count}个文件";
Console.WriteLine(log);
tempLog.Add(log);
if (File.Exists(Unpack_Output + $"//filelist.txt"))
File.Delete(Unpack_Output + $"//filelist.txt");
File.WriteAllLines(Unpack_Output + $"//filelist.txt", tempLog);
return true;
}
catch (Exception e)
{
WorkedDataLenght = 0;
return false;
}
}
static bool Repack_Mode0(string Repack_Input, string Unpack_Output)
{
string outputdir = Path.GetDirectoryName(Unpack_Output);
if (!Directory.Exists(outputdir))
{
Directory.CreateDirectory(outputdir);
Console.WriteLine($"创建目录{outputdir}");
}
if (File.Exists(Unpack_Output + $".txt"))
File.Delete(Unpack_Output + $".txt");
List<string> tempLog = new List<string>();
using (FileStream fs = new FileStream(Unpack_Output, FileMode.Create))
{
Repack_Mode0_logic(Repack_Input, fs, Unpack_Output, ref tempLog);
}
File.WriteAllLines(Unpack_Output + $".txt", tempLog);
return true;
}
static bool Repack_Mode0_logic(string Repack_Input, FileStream fs, string Unpack_Output, ref List<string> tempLog, bool skip_y = false)
{
string[] zipfiles = FileHelper.GetDirFile(Repack_Input).Where(w => w.ToLower().EndsWith(".zip")).ToArray();
List<byte[]> files = new List<byte[]>();
Console.WriteLine($"-----------原数据读取完毕-----------");
Console.WriteLine($"待处理文件:");
for (int i = 0; i < zipfiles.Length; i++)
{
if (!FileHelper.LoadFile(zipfiles[i], out byte[] filedata))
{
Console.WriteLine($"加载失败,文件:{zipfiles[i]}");
return false;
}
else
{
files.Add(filedata);
Console.WriteLine($"加载,待处理文件:{zipfiles[i]}Done");
}
}
if (!skip_y)
{
Console.WriteLine($"共{files.Count}个文件,是否处理? (y/n)");
string yn = Console.ReadLine();
if (yn.ToLower() != "y")
return false;
}
string log;
fs.WriteByte((byte)files.Count);
log = $"写入文件个数{files.Count}=>0x{files.Count.ToString("X")}";
Console.WriteLine(log);
tempLog.Add(log);
for (int i = 0; i < files.Count; i++)
{
int lenght = files[i].Length;
byte[] lenghtdata = HexHelper.uintToBytes(lenght);
int lenghtVal = Math.Min(2, lenghtdata.Length);
fs.Write(lenghtdata, 0, lenghtVal);
if (lenghtdata.Length == 1)
fs.WriteByte(0);
log = $"写入第[{i}]个文件大小{lenght}到文件头";
Console.WriteLine(log);
tempLog.Add(log);
}
log = $"文件头写入完毕";
for (int i = 0; i < files.Count; i++)
{
fs.Write(files[i], 0, files[i].Length);
log = $"写入第[{i}]个文件";
Console.WriteLine(log);
tempLog.Add(log);
}
log = $"Repack完毕{Unpack_Output}";
Console.WriteLine(log);
tempLog.Add(log);
return true;
}
static bool Unpack_Mode1(string Unpack_Input, string Unpack_Output)
{
Console.WriteLine($"开始处理{Unpack_Input}");
if (!Directory.Exists(Unpack_Output))
{
Directory.CreateDirectory(Unpack_Output);
Console.WriteLine($"创建目录{Unpack_Output}");
}
if (!FileHelper.LoadFile(Unpack_Input, out byte[] fulldata))
{
Console.WriteLine($"读取失败");
return false;
}
int subPackIdx = 0;
uint Pos = 0;
while (Pos < fulldata.Length)
{
Console.WriteLine($"----- 开始处理:SubPack[{subPackIdx}] -----");
string SubPackOutDir = Path.Combine(Unpack_Output, subPackIdx.ToString().PadLeft(4, '0'));
if (!Directory.Exists(SubPackOutDir))
{
Directory.CreateDirectory(SubPackOutDir);
Console.WriteLine($"创建目录{SubPackOutDir}");
}
if (!Unpack_Mode0_logic(fulldata, Pos, SubPackOutDir, out uint WorkedDataLenght))
{
Console.WriteLine($"SubPack[{subPackIdx}],处理失败");
return false;
}
Pos += WorkedDataLenght;
//处理非0x00
Console.WriteLine($"----- 处理:SubPack[{subPackIdx}]后续非0x00数据 -----");
List<byte> temp_Not0 = new List<byte>();
while (true)
{
if (Pos + 1 < fulldata.Length && fulldata[Pos + 1] != 0x00)
{
Pos += 1;
temp_Not0.Add(fulldata[Pos]);
}
else
{
break;
}
}
string tail_not0 = Path.Combine(SubPackOutDir, "tail_not0");
byte[] read_data_not0 = temp_Not0.ToArray();
using (FileStream fs = new FileStream(tail_not0, FileMode.Create))
{
fs.Write(read_data_not0, 0, read_data_not0.Length);
}
Console.WriteLine($"----- SubPack[{subPackIdx}]后续非0x00数据,Length:{read_data_not0.Length}存储到{tail_not0} -----");
//处理0x00
Console.WriteLine($"----- 处理:SubPack[{subPackIdx}]后续0x00数据 -----");
List<byte> temp_0 = new List<byte>();
while (true)
{
if (Pos + 1 < fulldata.Length && fulldata[Pos + 1] == 0x00)
{
Pos += 1;
temp_0.Add(fulldata[Pos]);
}
else
{
break;
}
}
string tail_0 = Path.Combine(SubPackOutDir, "tail");
byte[] read_data_0 = temp_0.ToArray();
using (FileStream fs = new FileStream(tail_0, FileMode.Create))
{
fs.Write(read_data_0, 0, read_data_0.Length);
}
Console.WriteLine($"----- SubPack[{subPackIdx}]后续0x00数据,Length:{read_data_0.Length}存储到{tail_0} -----");
Console.WriteLine($"----- 处理完毕:SubPack[{subPackIdx}] -----");
subPackIdx++;
Pos += 1;
}
return true;
}
readonly static int[] subpacklenght = { 14336, 7600, 1500, 28400 };
static bool Repack_Mode1(string Repack_Input, string Repack_Output)
{
string outputdir = Path.GetDirectoryName(Repack_Output);
if (!Directory.Exists(outputdir))
{
Directory.CreateDirectory(outputdir);
Console.WriteLine($"创建目录{outputdir}");
}
string[] dirs = Directory.GetDirectories(Repack_Input);
for (int i = 0; i < dirs.Length; i++)
Console.WriteLine($"发现目录:{dirs[i]}");
Console.WriteLine($"共{dirs.Length}个目录,是否处理? (y/n)");
string yn = Console.ReadLine();
if (yn.ToLower() != "y")
return false;
List<string> tempLog = new List<string>();
string log;
if (File.Exists(Repack_Output + $".txt"))
File.Delete(Repack_Output + $".txt");
using (FileStream fs = new FileStream(Repack_Output, FileMode.Create))
{
for (int subpack_idx = 0; subpack_idx < dirs.Length; subpack_idx++)
{
string subdir = dirs[subpack_idx];
log = $"-- 开始写入Subpack[{subpack_idx}]:下的zip包";
Console.WriteLine(log);
tempLog.Add(log);
Repack_Mode0_logic(subdir, fs, Repack_Output, ref tempLog, true);
log = $"-- 完成写入Subpack[{subpack_idx}]:下的zip包";
Console.WriteLine(log);
tempLog.Add(log);
string tail_not0 = Path.Combine(subdir, "tail_not0");
log = $"-- 开始写入Subpack[{subpack_idx}]:下的非0x00数据:{tail_not0}";
Console.WriteLine(log);
tempLog.Add(log);
if (!FileHelper.LoadFile(tail_not0, out byte[] inputbytes_not0))
{
Console.WriteLine($"读取失败");
return false;
}
fs.Write(inputbytes_not0, 0, inputbytes_not0.Length);
log = $"-- 完成写入Subpack[{subpack_idx}]:下的非0x00数据:length{inputbytes_not0.Length}";
Console.WriteLine(log);
tempLog.Add(log);
int targetSize = 0;
for (int sizeidx = 0; sizeidx <= subpack_idx; sizeidx++)
targetSize += subpacklenght[sizeidx];
long needAdd = (targetSize - fs.Length);
log = $"-- 需要补0x00长度:{needAdd}";
Console.WriteLine(log);
tempLog.Add(log);
if (needAdd < 0)
{
Console.WriteLine($"--Subpack[{subpack_idx}],超出MHi预设区间大小");
return false;
}
log = $"-- 开始写入Subpack[{subpack_idx}]:下的0x00数据";
Console.WriteLine(log);
tempLog.Add(log);
for (int i = 0; i < needAdd; i++)
fs.WriteByte(0x00);
log = $"-- 完成写入Subpack[{subpack_idx}]:下的0x00数据:length{needAdd}";
Console.WriteLine(log);
tempLog.Add(log);
}
}
File.WriteAllLines(Repack_Output + $".txt", tempLog);
return true;
}
}
}