/// <summary> /// Extract the root directory files from Base-{OS}.MPQ /// </summary> /// <returns></returns> private bool ExtractBaseMPQ() { Program.Log("Extracting Base MPQ..."); string baseMPQ = $"Base-{MFILDownloader.CurrentSession.OS}.mpq"; string baseMPQpath = Path.Combine(_dataDirectory, baseMPQ); if (!File.Exists(baseMPQpath)) { Program.Log($"{baseMPQ} not found!", ConsoleColor.Red); return(false); } using (var mpq = new MpqArchive(baseMPQpath, FileAccess.Read)) { if (!TryGetFileList(mpq, true, out var files)) { Program.Log($"{baseMPQ} missing ListFile, manual extraction required.", ConsoleColor.Red); return(false); } foreach (var file in files) { mpq.ExtractFile(file, Path.Combine(_repo.DefaultDirectory, file)); } } return(true); }
public static void ExtractListfiles(string to) { DirectoryInfo directory = new DirectoryInfo(ConfigurationManager.GameDir + "\\data\\"); FileInfo[] Archives = directory.GetFiles("*.mpq"); foreach (FileInfo fileinfo in Archives) { if (!File.Exists(to + "\\" + fileinfo.Name.Replace(".MPQ", ".txt"))) { using (MpqArchive archive = new MpqArchive(fileinfo.FullName, FileAccess.Read)) { archive.ExtractFile("(listfile)", to + "\\" + fileinfo.Name.Replace(".MPQ", ".txt")); } } } if (ConfigurationManager.Profile != 1) //Anything else than vanilla { if (!File.Exists(to + "\\" + "locale1.txt")) { using (MpqArchive archive = new MpqArchive(ConfigurationManager.GameDir + "\\data\\" + locale + "\\" + "locale-" + locale + ".mpq", FileAccess.Read)) { archive.ExtractFile("(listfile)", to + "\\" + "locale1.txt"); } } } }
/// <summary> /// Moves the files from the chunked archive to a flat file one /// </summary> /// <param name="archivename"></param> /// <param name="block"></param> private void DoFileSwap(string archivename, string block) { Directory.CreateDirectory("Temp"); string filename = Path.GetFileName(archivename); using (var mpq = MpqArchive.CreateNew(archivename, MpqArchiveVersion.Version3)) using (var tmp = new MpqArchive(block, FileAccess.Read, OpenArchiveFlags.BLOCK4)) { if (TryGetFileList(tmp, false, out var lf)) { _progressBar.Start(); string tempPath; for (int i = 0; i < lf.Count; i++) { using (var fs = tmp.OpenFile(lf[i])) { // incremental patch files can't be written directly with StormLib SFileCreateFile? if ((fs.TFileEntry.dwFlags & 0x100000u) != 0x100000u) { mpq.AddFileFromStream(fs); } else { tempPath = Path.Combine("Temp", lf[i]); Directory.CreateDirectory(Path.GetDirectoryName(tempPath)); tmp.ExtractFile(lf[i], tempPath); mpq.AddFileFromDisk(tempPath, lf[i], fs.TFileEntry.dwFlags); } } _progressBar.Update(filename, i / (float)lf.Count); if (i % 10000 == 0) { mpq.Flush(); } } } } Console.WriteLine("Emptying Temp Folder..."); DeleteDirectory("Temp"); _progressBar.Stop(); }
void BuildDataFiles() { using (var master = new MpqArchive(MasterPath, FileAccess.Read)) { using (var locale = new MpqArchive(LocalePath, FileAccess.Read)) { for (int i = 0; i < DataFiles.Length; i++) { string file = DataFiles[i], pathInMpq = $"UI\\{file}", tmpPath = $"{TempFolder}\\{file}", dataPath = $"{UmswePath}\\Data\\{file}", patch = $"{dataPath}.patch", addon = $"{dataPath}.addon"; //Why HasFile doesn't work? /*if(locale.HasFile(pathInMpq)) { * locale.ExtractFile(pathInMpq, tmpPath); * } else if(master.HasFile(pathInMpq)) { * master.ExtractFile(pathInMpq, tmpPath); * }*/ try { locale.ExtractFile(pathInMpq, tmpPath); } catch { master.ExtractFile(pathInMpq, tmpPath); } var data = new DataFile(tmpPath); if (File.Exists(patch)) { data.ApplyPatch(patch, PatchMode.Patch); } if (File.Exists(addon)) { data.ApplyPatch(addon, PatchMode.Addon); } data.SaveAs(tmpPath); } } } }
/** * Extracts file to disk * Overwrites disk file if needed * It extrats to "out/" folder */ private void Extract(String filename, MpqArchive archive) { try { Console.WriteLine("Extracting file: " + filename); if (!archive.HasFile(filename)) { Console.WriteLine("File did not exist in MPQ archive: " + filename + " skipping. . ."); return; } string destination = filename.Substring(1 + filename.LastIndexOf("\\")); archive.ExtractFile(filename, destination); if (File.Exists("out/" + filename)) { File.Delete("out/" + filename); Console.WriteLine("Overwrote existing file..."); } System.IO.Directory.CreateDirectory("out/" + filename); System.IO.Directory.Delete("out/" + filename); if (!File.Exists(destination)) { Console.WriteLine("Expected that extracted file exists, but extraction failed!"); return; } File.Copy(destination, "out/" + filename); if (!File.Exists("out/" + filename)) { Console.WriteLine("Expected that copied file exists, but copy failed!"); return; } File.Delete(destination); if (File.Exists(filename)) { Console.WriteLine("Failed to delete origin file!"); return; } Console.WriteLine("Extracted successfully to: " + filename); } catch (Exception ex) { Console.WriteLine("Failed to extract file " + filename + ": " + ex.Message); } }
// TODO: Add stream opening support /// <inheritdoc/> public Dictionary <string, List <string> > Scan(Scanner scanner, Stream stream, string file) { // If the mpq file itself fails try { string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempPath); using (MpqArchive mpqArchive = new MpqArchive(file, FileAccess.Read)) { // Try to open the listfile string listfile = null; MpqFileStream listStream = mpqArchive.OpenFile("(listfile)"); // If we can't read the listfile, we just return if (!listStream.CanRead) { return(null); } // Read the listfile in for processing using (StreamReader sr = new StreamReader(listStream)) { listfile = sr.ReadToEnd(); } // Split the listfile by newlines string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n'); // Loop over each entry foreach (string sub in listfileLines) { // If an individual entry fails try { string tempFile = Path.Combine(tempPath, sub); Directory.CreateDirectory(Path.GetDirectoryName(tempFile)); mpqArchive.ExtractFile(sub, tempFile); } catch { } } } // Collect and format all found protections var protections = scanner.GetProtections(tempPath); // If temp directory cleanup fails try { Directory.Delete(tempPath, true); } catch { } // Remove temporary path references Utilities.StripFromKeys(protections, tempPath); return(protections); } catch { } return(null); }
public static void UnpackMap(string inputMapPath, string outputFolderPath) { if (!File.Exists(inputMapPath)) { throw new FileNotFoundException(String.Format("Input map at {0} does not exist.", inputMapPath)); } if (Directory.Exists(outputFolderPath) && Directory.EnumerateFileSystemEntries(outputFolderPath).Any()) { throw new IOException(String.Format("Output folder at {0} is not empty.", outputFolderPath)); } // Strategy is as follows: // Copy map to the target location. Then extract all files, but convert the map into a container by deleting all the files inside. // Goal is that we are left with the MPQ container which contains all the other misc information which we are currently unable to manage. // In future, we might be able to generate the MPQ from scratch, but for now we will keep a big chunk of "unmanaged" data and focus // on the files we are able to manage. string containerPath = Path.Combine(outputFolderPath, FILENAME_CONTAINER); Directory.CreateDirectory(outputFolderPath); // Copy map to target location in preparation to convert it into a container File.Copy(inputMapPath, containerPath); string listFile = null; // Extract all files from the map and remove them from the container using (MpqArchive container = new MpqArchive(containerPath, FileAccess.ReadWrite)) using (MpqArchive archive = new MpqArchive(inputMapPath, FileAccess.Read)) { // Check if somebody is trying to unpack a container - lets avoid creating Matroshchkas if (archive.HasFile(DUMMY_FILENAME)) { throw new Exception("Input map seems to be a container rather than a packed map."); } using (MpqFileStream file = archive.OpenFile(MPQ_LISTFILE)) using (StreamReader sr = new StreamReader(file)) { listFile = sr.ReadToEnd(); } // We have to add a dummy file as otherwise the listfile gets deleted and somehow doesnt get restored... if (!container.HasFile(DUMMY_FILENAME)) { string dummyFilePath = Path.GetTempFileName(); try { using (StreamWriter listFileHandle = new StreamWriter(dummyFilePath)) { listFileHandle.WriteLine("Dummy file"); } container.AddFileFromDiskEx(dummyFilePath, DUMMY_FILENAME, MpqFileAddFileExFlags.MPQ_FILE_COMPRESS, MpqFileAddFileExCompression.MPQ_COMPRESSION_BZIP2, MpqFileAddFileExCompression.MPQ_COMPRESSION_NEXT_SAME); } finally { File.Delete(dummyFilePath); } } using (StringReader reader = new StringReader(listFile)) { string currentArchiveFile = string.Empty; do { currentArchiveFile = reader.ReadLine(); if (currentArchiveFile != null) { if (currentArchiveFile == DUMMY_FILENAME) { continue; } string targetPath = Path.Combine(outputFolderPath, currentArchiveFile.Trim('\\')); Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); archive.ExtractFile(currentArchiveFile, targetPath); container.RemoveFile(currentArchiveFile); } } while (currentArchiveFile != null); } container.Compact(MPQ_LISTFILE); } }