565 lines
20 KiB
C#
565 lines
20 KiB
C#
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;
|
||
}
|
||
|
||
}
|
||
}
|