/** * Imports a file to the archive. * Deletes/imports to overwrite. * It imports from "in/" folder */ private void Import(String filename, MpqArchive archive) { try { Console.WriteLine("Importing file: in/" + filename); if (!File.Exists("in/" + filename)) { Console.WriteLine("File does not exist: in/" + filename + " skipping. . ."); return; } if (archive.HasFile(filename)) { // We need to delete because stormlib doesn't overwrite Console.WriteLine("File already exists, deleting"); archive.DeleteFile(filename); } Console.WriteLine("Inserting file"); archive.AddFileFromDisk("in/" + filename, filename); if (!archive.HasFile(filename)) { Console.WriteLine("Expected import file exists, but did not!"); return; } Console.WriteLine("Successfully imported in/" + filename + " as " + filename); } catch (Exception ex) { Console.WriteLine("Failed to import file " + filename + ": " + ex.Message); } }
/// <summary> /// Attempts to read the listfile if present /// </summary> /// <param name="mpq"></param> /// <param name="filteredlist"></param> /// <returns></returns> private bool TryGetListFile(MpqArchive mpq, out List <string> filteredlist) { filteredlist = new List <string>(); if (mpq.HasFile(LISTFILE_NAME)) { using (var file = mpq.OpenFile(LISTFILE_NAME)) using (var sr = new StreamReader(file)) { if (!file.CanRead || file.Length <= 1) { return(false); } while (!sr.EndOfStream) { filteredlist.Add(sr.ReadLine().WoWNormalise()); } } // remove the MPQ documentation files filteredlist.RemoveAll(RemoveUnwantedFiles); filteredlist.TrimExcess(); return(filteredlist.Count > 0); } return(false); }
/// <summary> /// Attempts to return a list of all files in the archive /// </summary> /// <param name="mpq"></param> /// <param name="files"></param> /// <returns></returns> private bool TryGetFileList(MpqArchive mpq, bool removeLists, out List <string> files) { files = new List <string>(); if (!mpq.HasFile("(ListFile)")) { return(false); } using (var file = mpq.OpenFile("(ListFile)")) using (var sr = new StreamReader(file)) { if (!file.CanRead || file.Length == 0) { return(false); } string[] filenames = sr.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); files.AddRange(filenames); } if (removeLists) { files.RemoveAll(x => x.EndsWith(".lst")); } return(files.Count > 0); }
/** * 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); } }
/// <summary> /// Some alpha MPQs are hotswappable and only contain a single file and it's checksum /// </summary> /// <param name="mpq"></param> /// <param name="archivename"></param> private bool TryReadAlpha(MpqArchive mpq, string archivename) { // strip the local path and extension to get the filename var file = Path.ChangeExtension(GetInternalPath(archivename), null).WoWNormalise(); if (FileList.ContainsKey(file)) { return(true); } // add the filename as the listfile var internalname = Path.GetFileName(file); mpq.AddListFile(internalname); // read file if known if (mpq.HasFile(internalname)) { using var fs = mpq.OpenFile(internalname); if (fs.CanRead && fs.Length > 0) { var map = BlockTableEncoder.GetEMapFromExtension(file, fs.Length); if (!EncodingCache.TryGetRecord(MD5Hash.Parse(fs.GetMD5Hash()), file, out var record)) { record = BlockTableEncoder.EncodeAndExport(fs, map, Options.TempDirectory, file); EncodingCache.AddOrUpdate(record); } record.EBlock.EncodingMap = map; FileList.TryAdd(file, record); return(true); } } return(false); }
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); } }