private static string GetFileMD5(string path) { if (!XLPack.IsFileExist(path)) { return(""); } var position = XLPack.FOpen(path, "r"); XLPack.afs_md5_ctx md5info = new XLPack.afs_md5_ctx(); var res = XLPack.FGetMD5(position, ref md5info); XLPack.FClose(ref position); return(res ? BitConverter.ToString(md5info.md5).Replace("-", "").ToLower() : ""); }
private static XLPack.pack_stat_t GetFileStat(string path) { var stat = new XLPack.pack_stat_t(); if (!XLPack.IsFileExist(path)) { return(stat); } var position = XLPack.FOpen(path, "r"); var res = XLPack.FGetStat(position, ref stat); XLPack.FClose(ref position); return(stat); }
private static void MountFileSystem(string path) { var pack = new FileInfo(path); _fsPath = pack.DirectoryName; Log("Info", "Mount /fs ..."); _fsHandler = XLPack.Mount("/fs", _fsPath, true); Log("Info", "Done"); Log("Info", "Mount /master ..."); _masterHandler = XLPack.Mount("/master", path, true); Log("Info", "Done"); }
private static bool SetFileMD5(string path, string hash) { if (!XLPack.IsFileExist(path)) { return(false); } XLPack.afs_md5_ctx md5info = new XLPack.afs_md5_ctx(); md5info.md5 = StringToByteArray(hash); var position = XLPack.FOpen(path, "r"); // fsetmd5 00001111222233334444555566667777 /master/bin32/zlib1.dll var res = XLPack.FSetMD5(position, ref md5info); XLPack.FClose(ref position); return(res); }
private static bool ReCalculateFileMD5(string path) { if (!XLPack.IsFileExist(path)) { return(false); } var position = XLPack.FOpen(path, "r"); long fileSize = XLPack.FSize(position); const int bufSize = 0x4000; byte[] buffer = new byte[bufSize]; IntPtr bufPtr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); // TODO: Do this without reading the entire file into memory to calculate the MD5 // Maybe try to use the XLPack.DLL's MD5Init, MD5Update and MD5 Finalize functions ? // Using ChunkedMemoryStream instead of MemoryStream to hopefully avoid outofmemory errors on large files ChunkedMemoryStream ms = new ChunkedMemoryStream(); long readTotalSize = 0; while (readTotalSize < fileSize) { long readSize = fileSize - readTotalSize; if (readSize > bufSize) { readSize = bufSize; } XLPack.FRead(position, bufPtr, readSize); ms.Write(buffer, 0, (int)readSize); // readSize should never be out of int range, so it's safe to cast it readTotalSize += readSize; } XLPack.FClose(ref position); ms.Position = 0; MD5 md5Hash = MD5.Create(); string md5String = GetMd5Hash(md5Hash, ms).Replace("-", "").ToLower(); ms.Dispose(); var res = SetFileMD5(path, md5String); return(res); }
private static List <(string, bool)> GetFiles(string path) { var result = new List <(string, bool)>(); var file = path + "*"; var fd = new XLPack.afs_finddata(); var findHandle = XLPack.FindFirst(file, ref fd); if (findHandle != -1) { do { var fileName = Marshal.PtrToStringAnsi(XLPack.GetFileName(ref fd)); var tempFile = path + fileName; var isDirectory = !XLPack.IsFileExist(tempFile); result.Add((tempFile, isDirectory)); } while (XLPack.FindNext(findHandle, ref fd) != -1); } XLPack.FindClose(findHandle); return(result); }
static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("Start: XLPakTool.exe <path_to_game_pak>"); return; } var gamePakPath = args[0]; Console.Title = "XLPakTool - " + gamePakPath; Log("Info", "Create file system..."); if (XLPack.CreateFileSystem()) { Log("Info", "Done"); Log("Info", "Connect log handler..."); _logHandler = XLPack.SetFileLogHandler("pack.log", LogHandler); Log("Info", "Done"); MountFileSystem(gamePakPath); Thread.Sleep(1000); while (true) { Console.Write($"~{_globalPath}$ "); var command = Console.ReadLine(); var parse = CommandParser(command); if (parse.Length <= 0) { continue; } var cmd = parse[0]; var cmdArgs = new string[parse.Length - 1]; if (cmdArgs.Length > 0) { Array.Copy(parse, 1, cmdArgs, 0, cmdArgs.Length); } if (cmd == "quit") { break; } if (cmd == "exit") { break; } switch (cmd) { case "help": Log("Help", "cd <path> -> move at folders"); Log("Help", "ls [path] -> get files"); Log("Help", "cp <scr> <dest> -> copy file from src to dest"); Log("Help", "rm <path> -> remove path"); Log("Help", "fstat <file path> -> Get file stat (doesn't work if one of the fields is missing information)"); Log("Help", "fsize <file path> -> Get file size"); Log("Help", "fgetmd5 <file path> -> Get file md5 as string"); Log("Help", "fstat1 <file path> -> Get file timestamps"); Log("Help", "makemd5 <file path> -> Re-calculate and Set the MD5 of a file"); Log("Help", "fsetmd5 <hash> <file path> -> Manually enter a value for a file's md5 field"); Console.WriteLine("--------------------------------"); Log("Help", "To export file(s)/dir:"); Log("Help", "cp <src> /fs/<dest>"); Log("Help", "To import file(s)/dir:"); Log("Help", "cp /fs/<src> <dest>"); break; case "cd": if (cmdArgs.Length == 0) { Log("Info", "cd <toDir>"); } else { var cmdPath = cmdArgs[0]; var prePath = _globalPath; _globalPath = AbsolutePath(cmdPath); if (!_globalPath.EndsWith("/") && !_globalPath.EndsWith("\\")) { _globalPath += "/"; } if (!IsDirectory(_globalPath)) { _globalPath = prePath; } } break; case "ls": var path = _globalPath; if (cmdArgs.Length > 0) { path = AbsolutePath(cmdArgs[0]); path += "/"; } var files = GetFiles(path); if (files.Count > 0) { foreach (var(file, isDirectory) in files) { if (isDirectory) { Console.BackgroundColor = ConsoleColor.DarkBlue; } Console.WriteLine(file.Replace(path, "")); Console.ResetColor(); } } else { Console.WriteLine("------ EMPTY ------"); } break; case "cp": if (cmdArgs.Length < 2) { Log("Info", "cp <src> <dest>"); } else { var src = AbsolutePath(cmdArgs[0]); var dest = AbsolutePath(cmdArgs[1]); bool exist; if (src.StartsWith("/fs")) { var realyPath = src.Replace("/fs", _fsPath); exist = File.Exists(realyPath); if (!exist) { exist = Directory.Exists(realyPath); } } else { exist = IsPathExist(src); } if (!exist) { Log("Warn", "Bad source path: {0}", src); } else { var dir = IsDirectory(src); var result = dir ? XLPack.CopyDir(src, dest) : XLPack.Copy(src, dest); Console.WriteLine(result ? "Done" : "Copy failed..."); } } break; case "rm": if (cmdArgs.Length == 0) { Log("Info", "rm <path>"); } else { path = AbsolutePath(cmdArgs[0]); if (IsDirectory(path)) { Console.WriteLine(XLPack.DeleteDir(path) ? "Done" : "Remove failed..."); } else { Console.WriteLine(XLPack.FDelete(path) ? "Done" : "Remove failed..."); } } break; case "fstat": if (cmdArgs.Length == 0) { Log("Info", "fstat <file path>"); } else { path = cmdArgs[0]; var temp = GetFileStat2(path); if (temp == null) { Log("Warn", "[File] Doesn't exist or get stat..."); } else { Log("File", path); Log("File", $"Size: {temp.Size}"); Log("File", $"CreationTime: {temp.CreateTime}"); Log("File", $"ModifiedTime: {temp.ModifyTime}"); Log("File", $"MD5: {temp.Hash}"); } } break; case "fstat1": if (cmdArgs.Length == 0) { Log("Info", "fstat <file path>"); } else { path = cmdArgs[0]; var temp = GetFileStat(path); Log("File", $"CreationTime: {DateTime.FromFileTime(temp.creationTime)}"); Log("File", $"ModifiedTime: {DateTime.FromFileTime(temp.modifiedTime)}"); } break; case "fsize": if (cmdArgs.Length == 0) { Log("Info", "fsize <file path>"); } else { path = cmdArgs[0]; var temp = GetFileSize(path); if (temp < 0) { Log("Warn", "[File] Doesn't exist ..."); } else { Log("File", $"Size: {temp}"); } } break; case "fgetmd5": if (cmdArgs.Length == 0) { Log("Info", "fgetmd5 <file path>"); } else { path = cmdArgs[0]; var temp = GetFileMD5(path); if (temp == null) { Log("Warn", "[File] Doesn't exist ..."); } else { Log("File", $"MD5: {temp}"); } } break; case "fsetmd5": if (cmdArgs.Length < 2) { Log("Info", "fsetmd5 <md5hash> <file path>"); } else { var hash = cmdArgs[0]; path = cmdArgs[1]; if (!SetFileMD5(path, hash)) { Log("Warn", "[File] Doesn't exist ..."); } else { Log("File", $"File MD5 updated to {hash}"); } } break; case "makemd5": if (cmdArgs.Length == 0) { Log("Info", "makemd5 <file path>"); } else { path = cmdArgs[0]; if (!ReCalculateFileMD5(path)) { Log("Warn", "[File] Doesn't exist or failed to update ..."); } else { Log("File", $"File MD5 updated"); } } break; case "fusemd5": if (cmdArgs.Length == 0) { Log("Info", "fusemd5 <file path>"); } else { path = cmdArgs[0]; var temp = UseMD5(path); Log("File", $"UseMD5: {temp}"); } break; case "struct": var tree = new TreeDictionary("/master"); GetFileSystemStruct(tree); // TODO ... save to file... break; case "exportfilelist": ExportFileList(); break; } } Destroy(); } else { Log("Error", "Cannot create file system"); } }
private static void DestroyFileSystem() { XLPack.Unmount(_masterHandler); XLPack.Unmount(_fsHandler); }
private static void Destroy() { DestroyFileSystem(); XLPack.DestroyFileLogHandler(_logHandler); XLPack.DestroyFileSystem(); }