diff --git a/FileHelper.cs b/FileHelper.cs new file mode 100644 index 0000000..42639f4 --- /dev/null +++ b/FileHelper.cs @@ -0,0 +1,56 @@ +using System.Text; + +namespace MHiRepacker +{ + public class FileHelper + { + public static bool LoadFile(string FilePath, out byte[] data) + { + using (FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read)) + { + try + { + byte[] buffur = new byte[fs.Length]; + fs.Read(buffur, 0, (int)fs.Length); + fs.Close(); + data = buffur; + return true; + } + catch (Exception ex) + { + data = null; + return false; + } + } + } + + public static string[] GetDirFile(string Path) + { + return Directory.GetFiles(Path); + } + + public static byte[] String2Byte(string value) + { + return Encoding.Default.GetBytes(value); + } + public static bool SaveFile(string FilePath, byte[] buffer) + { + try + { + //创建一个文件流 + using (FileStream wfs = new FileStream(FilePath, FileMode.Create)) + { + //将byte数组写入文件中 + wfs.Write(buffer, 0, buffer.Length); + //所有流类型都要关闭流,否则会出现内存泄露问题 + wfs.Close(); + return true; + } + } + catch + { + return false; + } + } + } +} diff --git a/HexHelper.cs b/HexHelper.cs new file mode 100644 index 0000000..4d51605 --- /dev/null +++ b/HexHelper.cs @@ -0,0 +1,226 @@ +using System.Text; + +namespace MHiRepacker +{ + public class HexHelper + { + + public static byte[] CopyByteArr(byte[] src) + { + byte[] target = new byte[src.Length]; + //加载数据 + target = new byte[src.Length]; + for (int i = 0; i < src.Length; i++) + target[i] = src[i]; + return target; + } + + /// <summary> + /// 读取byte[]数据 + /// </summary> + /// <param name="src"></param> + /// <param name="lenght"></param> + /// <param name="offset"></param> + /// <returns></returns> + public static byte[] ReadBytes(byte[] src, int lenght, int offset = 0) + { + byte[] data = new byte[lenght]; + for (int i = 0; i < lenght; i++) + { + data[i] = src[offset + i]; + } + return data; + } + + /** + * byte[]转换int byte高位在前 + */ + public static int bytesToInt(byte[] src,int lenght, int offset = 0) + { + if (lenght == 1) + return src[offset + 0]; + + byte[] data = new byte[lenght]; + for (int i = 0; i < lenght; i++) + { + data[i] = src[offset + i]; + } + + if(lenght == 2) + return BitConverter.ToInt16(data, 0); + else //if (lenght == 4) + return BitConverter.ToInt32(data, 0); + } + + /** + * byte[]转换int byte高位在前 + */ + public static uint bytesToUInt(byte[] src, int lenght, int offset = 0) + { + if (lenght == 1) + return src[offset + 0]; + + byte[] data = new byte[lenght]; + for (int i = 0; i < lenght; i++) + { + data[i] = src[offset + i]; + } + + if (lenght == 2) + return BitConverter.ToUInt16(data, 0); + else //if (lenght == 4) + return BitConverter.ToUInt32(data, 0); + } + + /** + * int 转 byte[] byte高位在前 + */ + public static byte[] intToBytes(int value) + { + return BitConverter.GetBytes(value); + } + + /** + * 从字节读取字符串 + */ + public static string ReadBytesToString(byte[] src, int Start, Encoding encoding = null) + { + List<byte> bytes = new List<byte>(); + + int index = 0; + while (true) + { + bytes.Add(src[Start + index]); + + if (src[Start + index + 1] == 0x00) + break; + + index++; + } + if (encoding == null) + encoding = Encoding.GetEncoding("Shift-JIS"); + string str = encoding.GetString(bytes.ToArray()); + return str; + } + + + /** + * 从字节读取字符串 + */ + public static string ReadBytesToString(byte[] src, Encoding encoding = null) + { + if (encoding == null) + encoding = Encoding.GetEncoding("Shift-JIS"); + string str = encoding.GetString(src.ToArray()); + return str; + } + + + /** + * 写入int到byte[] byte高位在前 + */ + public static void ModifyIntHexToBytes(byte[] srcdata, int targetvalue,int startoffset, int srclenght) + { + byte[] targetVal = intToBytes(targetvalue); + + //抹去数据 + for (int i = 0; i < srclenght; i++) + srcdata[startoffset + i] = 0x00; + + for (int i = 0; i < targetVal.Length && i < srclenght; i++) + srcdata[startoffset + i] = targetVal[i]; + } + + + /** + * 写入byte[]到byte[] byte高位在前 + */ + public static void ModifyDataToBytes(byte[] srcdata, byte[] targetVal, int startoffset) + { + //抹去数据 + for (int i = 0; i < targetVal.Length; i++) + srcdata[startoffset + i] = 0x00; + + for (int i = 0; i < targetVal.Length && i < targetVal.Length; i++) + srcdata[startoffset + i] = targetVal[i]; + } + + + + /** + * 对比数据 + */ + public static bool CheckDataEquals(byte[] srcdata, byte[] targetVal, int startoffset) + { + byte[] temp = new byte[targetVal.Length]; + for (int i = 0; i < targetVal.Length && i < targetVal.Length; i++) + temp[i] = srcdata[startoffset + i]; + + return Array.Equals(targetVal, temp); + } + + /// <summary> + /// 另一种16进制转10进制的处理方式,Multiplier参与*16的循环很巧妙,对Multiplier的处理很推荐,逻辑统一 + /// </summary> + /// <param name="HexaDecimalString"></param> + /// <returns></returns> + public static int HexaToDecimal(string HexaDecimalString) + { + int Decimal = 0; + int Multiplier = 1; + + for (int i = HexaDecimalString.Length - 1; i >= 0; i--) + { + Decimal += HexaToDecimal(HexaDecimalString[i]) * Multiplier; + Multiplier *= 16; + } + return Decimal; + } + + static int HexaToDecimal(char c) + { + switch (c) + { + 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': + case 'a': + return 10; + case 'B': + case 'b': + return 11; + case 'C': + case 'c': + return 12; + case 'D': + case 'd': + return 13; + case 'E': + case 'e': + return 14; + case 'F': + case 'f': + return 15; + } + return -1; + } + } +} diff --git a/MHiRepacker.csproj b/MHiRepacker.csproj new file mode 100644 index 0000000..3c66bdd --- /dev/null +++ b/MHiRepacker.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net9.0</TargetFramework> + <ImplicitUsings>enable</ImplicitUsings> + <PublishAot>true</PublishAot> + <Nullable>enable</Nullable> + </PropertyGroup> + +</Project> diff --git a/MHiRepacker.sln b/MHiRepacker.sln new file mode 100644 index 0000000..3fc8108 --- /dev/null +++ b/MHiRepacker.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MHiRepacker", "MHiRepacker.csproj", "{DD424EE8-2243-4916-86C8-06BE58B6F4DD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD424EE8-2243-4916-86C8-06BE58B6F4DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD424EE8-2243-4916-86C8-06BE58B6F4DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD424EE8-2243-4916-86C8-06BE58B6F4DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD424EE8-2243-4916-86C8-06BE58B6F4DD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..dd303a1 --- /dev/null +++ b/Program.cs @@ -0,0 +1,259 @@ +using System; +using System.Drawing; +using System.Reflection; +using System.Text; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace MHiRepacker +{ + internal class Program + { + static string loc = Path.GetDirectoryName(AppContext.BaseDirectory) + "\\"; + static string Unpack_Input = loc + "Unpack_Input"; + static string Unpack_Output = loc + "Unpack_Output"; + static string Repack_Input = loc + "Repack_Input"; + static string Repack_Output = loc + "Repack_Output"; + static string exceldata = "exceldata.dat"; + + static void Main(string[] args) + { + string title = $"MHiRepacker Ver.1.0 By 皓月云 axibug.com"; + Console.Title = title; + Console.WriteLine(title); + + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + Encoding shiftencode = Encoding.GetEncoding("Shift-JIS"); + + + while (true) + { + Console.WriteLine("进行的操作:[1]解包Unpack [2]打包Repack"); + if (int.TryParse(Console.ReadLine(), out int func)) + { +#if !DEBUG + try +#endif + { + switch (func) + { + case 1: + Unpack(); + break; + case 2: + Repack(); + break; + } + } + +#if !DEBUG + catch (Exception ex) + { + Console.WriteLine("处理异常:" + ex.ToString()); + } +#endif + } + } + } + + static void Unpack() + { + if (!Directory.Exists(Unpack_Input)) + { + Console.WriteLine("Unpack_Input文件不存在"); + return; + } + + if (!Directory.Exists(Unpack_Output)) + { + Console.WriteLine("Unpack_Output文件不存在"); + return; + } + if (!File.Exists(Unpack_Input + "//" + exceldata)) + { + Console.WriteLine($"{Unpack_Input + "//" + exceldata}不存在"); + return; + } + Console.WriteLine($"是否开始处理{exceldata}"); + if (!FileHelper.LoadFile(Unpack_Input + "//" + exceldata, out byte[] data)) + { + Console.WriteLine($"读取失败"); + return; + } + + if (!DoUnpack(data)) + { + Console.WriteLine($"处理失败"); + return; + } + return; + } + + static bool DoUnpack(byte[] data) + { + int StartHead = 0x01; + + byte[] StartHeadEndArr = { 0x50, 0x4B, 0x03, 0x04, 0x14 };//PK + + List<string> tempLog = new List<string>(); + int pos = StartHead; + bool CheckStartEnd(byte[] temp, int startIdx) + { + for (int i = 0; i < StartHeadEndArr.Length; i++) + { + if (StartHeadEndArr[i] != temp[startIdx++]) + return true; + } + return false; + } + + List<int> SizeList = new List<int>(); + try + { + int idx = 0; + int StartContentPtr = 0; + string log; + tempLog.Add("文件头读取:"); + while (CheckStartEnd(data, pos) && CheckStartEnd(data, pos + 1)) + { + int size = HexHelper.bytesToInt(data, 2, pos); + SizeList.Add(size); + log = $"lenght:[{idx++}]=>{size}({size.ToString("X")})| byte src: 0x{data[pos].ToString("X")} 0x{data[pos + 1].ToString("X")}"; + Console.WriteLine(log); + tempLog.Add(log); + pos += 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(data, StartContentPtr, SizeList[i]); + } + StartContentPtr += SizeList[i]; + + log = $"写入{filename}"; + Console.WriteLine(log); + tempLog.Add(log); + } + + + log = $"Unpack完毕,共{SizeList.Count}个.zip"; + 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) + { + return false; + } + } + + + static void Repack() + { + if (!Directory.Exists(Repack_Input)) + { + Console.WriteLine("Repack_Input文件不存在"); + return; + } + + if (!Directory.Exists(Unpack_Output)) + { + Console.WriteLine("Unpack_Output文件不存在"); + return; + } + + + if (!DoRepack()) + { + Console.WriteLine($"处理失败"); + return; + } + return; + } + + static bool DoRepack() + { + int StartHead = 0x01; + string[] zipfiles = FileHelper.GetDirFile(Unpack_Output).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"); + } + } + + Console.WriteLine($"共{files.Count}个文件,是否处理? (y/n)"); + string yn = Console.ReadLine(); + if (yn.ToLower() != "y") + return false; + + List<string> tempLog = new List<string>(); + string log; + using (FileStream fs = new FileStream(Repack_Output + "//" + exceldata, FileMode.Create)) + { + 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.intToBytes(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完毕:{Repack_Output + "//" + exceldata}"; + Console.WriteLine(log); + tempLog.Add(log); + if (File.Exists(Repack_Output + $"//filelist.txt")) + File.Delete(Repack_Output + $"//filelist.txt"); + + File.WriteAllLines(Repack_Output + $"//filelist.txt", tempLog); + return true; + } + } +} diff --git a/README.md b/README.md index 6c88cf1..5199116 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # MHiRepacker Monster Hunter i for SH Unpack/Repacker Tools -"怪物猎人i for 夏普"解包打包工具 \ No newline at end of file +"怪物猎人i for 夏普"解包打包工具 + + +感谢"猪突猛进锅"分析exceldata.dat文件 \ No newline at end of file