private static byte[] GetMpqArchiveFileBytes(MpqArchive archive, string fileName) { using (var mpqStream = archive.OpenFile(archive.Single(i => i.Filename == fileName))) { var buffer = new byte[mpqStream.Length]; mpqStream.Read(buffer, 0, buffer.Length); return buffer; } }
/// <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(); }
public ItemTag(MpqArchive archive, MpqEntry mpqEntry, string archiveName = null) { MpqEntry = mpqEntry; FileName = mpqEntry.FileName; ArchiveName = archiveName ?? string.Empty; OriginalFileStream = archive.OpenFile(mpqEntry); if (!OriginalFileStream.CanRead) { OriginalFileStream.Dispose(); Status = MapFileStatus.Locked; } else { Adapter = AdapterFactory.GetAdapter(OriginalFileStream, FileName); Status = Adapter is null ? MapFileStatus.Unknown : MapFileStatus.Pending; } }
public static void GenerateMainListFileFromMPQ() { //Only generate list if empty if (MainListFile.Count == 0) { DirectoryInfo directory = new DirectoryInfo(ConfigurationManager.GameDir + "\\data\\"); FileInfo[] Archives = directory.GetFiles("*.mpq", SearchOption.TopDirectoryOnly); string listFile; foreach (FileInfo fileinfo in Archives) { try { using (MpqArchive archive = new MpqArchive(fileinfo.FullName, FileAccess.Read)) { using (MpqFileStream file = archive.OpenFile("(listfile)")) using (StreamReader sr = new StreamReader(file)) { listFile = sr.ReadToEnd(); MainListFile.Add(listFile.ToLower() + ";" + fileinfo.Name); } } } catch { throw new Exception("Could not read: \"" + fileinfo.FullName + "\"."); } } //Add locale to the listfile: if (ConfigurationManager.Profile != 1) //Anything else than Vanilla { using (MpqArchive archive = new MpqArchive(ConfigurationManager.GameDir + "\\data\\" + locale + "\\" + "locale-" + locale + ".mpq", FileAccess.Read)) { using (MpqFileStream file = archive.OpenFile("(listfile)")) using (StreamReader sr = new StreamReader(file)) { listFile = sr.ReadToEnd(); MainListFile.Add(listFile.ToLower() + ";" + "locale1.txt"); //.txt because i need an extension, that's how i coded the damn thing, and that's how it will stay for the moment } } } } }
/// <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); }
/// <summary> /// Parses the archive file. /// </summary> /// <param name="mpq"></param> /// <param name="filename"></param> /// <param name="overridename">Alpha MPQ filename override.</param> /// <returns></returns> private IFormat ReadFileImpl(MpqArchive mpq, string filename, string overridename = null) { using var md5 = MD5.Create(); using var stream = mpq.OpenFile(overridename ?? filename); if (stream == null || !stream.CanRead || stream.Length <= 1) { return(null); } // validate filesize limit if (_options.MaxFileSize > 0 && stream.Length > _options.MaxFileSize) { return(null); } Structures.Meta.FileInfo entry = new Structures.Meta.FileInfo() { Build = _build.Build, Name = filename.WoWNormalize() }; if (_options.ParseMode.HasFlag(ParseMode.FileInfo)) { entry.Checksum = stream.GetMd5Hash(); if (string.IsNullOrWhiteSpace(entry.Checksum) || entry.Checksum == EMPTY_CHECKSUM) { entry.Checksum = md5.ComputeHash(stream).ToChecksum(); } entry.Created = stream.CreatedDate; entry.Size = (uint)stream.Length; } stream.FileName = filename; using var bs = new BufferedStream(stream); return(_fileReader.Read(bs, entry)); }
// 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 Stream OpenRead(string file) { return(mpqArchive.OpenFile(file)); }
public static bool ExtractDBC() { try { Logger.Notice("Extracting DBC files..."); //Check if dbc.MPQ exist. if (!File.Exists(Paths.DBCMPQPath)) { Logger.Error($"Unable to locate dbc.MPQ at path {Paths.DBCMPQPath}, please check Config.txt and set a proper installation path."); return(false); } // Clean up output directory if neccesary. if (Directory.Exists(Paths.DBCLoadPath)) { Directory.Delete(Paths.DBCLoadPath, true); } using (MpqArchive archive = new MpqArchive(Paths.DBCMPQPath)) { archive.AddListfileFilenames(); foreach (var entry in archive) { if (!string.IsNullOrEmpty(entry.Filename)) { var outputFileName = Paths.Combine(Paths.DBCLoadPath, Path.GetFileName(entry.Filename)); var outputPlainName = Path.GetFileNameWithoutExtension(outputFileName); if (File.Exists(outputFileName)) { File.Delete(outputFileName); } if (InterestedDBC.Any(name => outputPlainName.ToLower().Equals(name.ToLower()))) { byte[] buf = new byte[0x40000]; using (Stream streamIn = archive.OpenFile(entry)) { using (Stream streamOut = new FileStream(outputFileName, FileMode.Create)) { while (true) { int cb = streamIn.Read(buf, 0, buf.Length); if (cb == 0) { break; } streamOut.Write(buf, 0, cb); } streamOut.Close(); } } Logger.Success($"Extracted DBC file [{entry.Filename}]."); } } } } return(true); } catch (Exception ex) { Logger.Error(ex.Message); Logger.Error(ex.StackTrace); if (ex.InnerException != null) { Logger.Error(ex.InnerException.Message); Logger.Error(ex.InnerException.StackTrace); } } return(false); }
public static Stream ReadThisFile(string filename) { Stream stream = null; if (usingCasc) //CASC { stream = cascHandler.OpenFile(filename); } else //MPQ { //Find the goddamn file in the archive hell int index = MainListFile.FindIndex(a => a.Contains(filename.ToLower())); if (index != -1) { //Get the archive in which the requested file resides string archive = MainListFile[index]; archive = archive.Substring(archive.LastIndexOf(';', archive.Length - 2) + 1); switch (archive.Substring(0, archive.Length - 4).Replace("-", "")) { //Mysts case "expansion4": stream = expansion4.OpenFile(filename); break; case "model": stream = model.OpenFile(filename); break; //Cataclysm case "art": stream = art.OpenFile(filename); break; case "expansion1": stream = expansion1.OpenFile(filename); break; case "expansion2": stream = expansion2.OpenFile(filename); break; case "expansion3": stream = expansion3.OpenFile(filename); break; case "world": stream = world.OpenFile(filename); break; case "world2": stream = world2.OpenFile(filename); break; case "locale1": stream = locale1.OpenFile(filename); break; //Lich King case "common": stream = common.OpenFile(filename); break; case "common2": stream = common2.OpenFile(filename); break; case "expansion": stream = expansion.OpenFile(filename); break; case "lichking": stream = lichking.OpenFile(filename); break; case "patch": stream = patch.OpenFile(filename); break; case "patch2": stream = patch2.OpenFile(filename); break; case "patch3": stream = patch3.OpenFile(filename); break; //Vanilla case "base": stream = baseMPQ.OpenFile(filename); break; case "dbc": stream = dbc.OpenFile(filename); break; case "interface": stream = interfaceMPQ.OpenFile(filename); break; case "misc": stream = misc.OpenFile(filename); break; case "sound": stream = sound.OpenFile(filename); break; case "terrain": stream = terrain.OpenFile(filename); break; case "texture": stream = texture.OpenFile(filename); break; case "wmo": stream = wmo.OpenFile(filename); break; } } else { //Missing file stream = null; } } return(stream); }
public Map(string filename) { MapPath = filename; using (FileStream fs = new FileStream(filename, FileMode.Open)) { byte[] d = new byte[fs.Length]; fs.Read(d, 0, d.Length); fs.Seek(0, SeekOrigin.Begin); this.MapSize = BitConverter.GetBytes((int)fs.Length); this.MapInfo = new CRC32().ComputeHash(d, 0, d.Length); using (MpqArchive a = new MpqArchive(fs, true)) { uint CRCVal = 0; SHA1Managed sha = new SHA1Managed(); byte[] commonJData, blizzardJData; if (a.FileExists("Scripts\\common.j")) { using (var commonOverload = a.OpenFile("Scripts\\common.j")){ var ms = new MemoryStream(); commonOverload.CopyTo(ms); commonJData = ms.ToArray(); ms.Dispose(); } } else { commonJData = File.ReadAllBytes("dep/common.j"); } if (a.FileExists("Scripts\\blizzard.j")) { using (var blizzardOverload = a.OpenFile("Scripts\\blizzard.j")){ var ms = new MemoryStream(); blizzardOverload.CopyTo(ms); blizzardJData = ms.ToArray(); ms.Dispose(); } } else { blizzardJData = File.ReadAllBytes("dep/blizzard.j"); } CRCVal = CRCVal ^ XORRotateLeft(commonJData); CRCVal = CRCVal ^ XORRotateLeft(blizzardJData); sha.TransformBlock(commonJData, 0, commonJData.Length, commonJData, 0); sha.TransformBlock(blizzardJData, 0, blizzardJData.Length, blizzardJData, 0); var magicBytes = new byte[] { 0x9e, 0x37, 0xf1, 0x03 }; uint magicInt = 0x03F1379E; CRCVal = ROTL(CRCVal, 3); CRCVal = ROTL(CRCVal ^ magicInt, 3); sha.TransformBlock(magicBytes, 0, magicBytes.Length, magicBytes, 0); string[] filenames = { "war3map.j", "scripts\\war3map.j", "war3map.w3e", "war3map.wpm", "war3map.doo", "war3map.w3u", "war3map.w3b", "war3map.w3d", "war3map.w3a", "war3map.w3q" }; var foundScript = false; foreach (string fn in filenames) { if (foundScript && fn == filenames[2]) { continue; } if (!a.FileExists(fn)) { continue; } using (MpqStream s = a.OpenFile(fn)){ var ms = new MemoryStream(); s.CopyTo(ms); var fdata = ms.ToArray(); ms.Dispose(); CRCVal = ROTL(CRCVal ^ XORRotateLeft(fdata), 3); sha.TransformBlock(fdata, 0, fdata.Length, fdata, 0); } } MapCRC = BitConverter.GetBytes(CRCVal); sha.TransformFinalBlock(new byte[] {}, 0, 0); MapSha = sha.Hash; //loading actual map shit now int MapFlags; using (MpqStream m = a.OpenFile("war3map.w3i")){ BinaryReader br = new BinaryReader(m); var FileFormat = br.ReadInt32(); if (FileFormat != 18 && FileFormat != 25) { throw new Exception("Unknown w3i file format " + FileFormat); } //most of these are practically garbage, but still fun to have :) int g_NumSaves = br.ReadInt32(); int g_EditorVer = br.ReadInt32(); string g_MapName = ConvertUtils.parseStringZ(br); string g_MapAuthor = ConvertUtils.parseStringZ(br); string g_MapDesc = ConvertUtils.parseStringZ(br); string g_MapReccomendedPlayers = ConvertUtils.parseStringZ(br); byte[] g_CameraBounds = br.ReadBytes(32); byte[] g_CameraBoundsExt = br.ReadBytes(16); int g_MapWidth = MapWidth = br.ReadInt32(); int g_MapHeight = MapHeight = br.ReadInt32(); int g_MapFlags = MapFlags = br.ReadInt32(); byte g_MapGroundType = br.ReadByte(); bool g_TFTLoading = FileFormat == 25; int g_LoadingScreenId; string g_LoadingScreenPath = ""; if (!g_TFTLoading) { g_LoadingScreenId = br.ReadInt32(); } else { g_LoadingScreenId = br.ReadInt32(); g_LoadingScreenPath = ConvertUtils.parseStringZ(br); } string g_LoadingText = ConvertUtils.parseStringZ(br); string g_LoadingTitle = ConvertUtils.parseStringZ(br); string g_LoadingSubTitle = ConvertUtils.parseStringZ(br); int g_PrologueScreenId; string g_PrologueScreenPath = ""; if (!g_TFTLoading) { g_PrologueScreenId = br.ReadInt32(); } else { g_PrologueScreenId = br.ReadInt32(); g_PrologueScreenPath = ConvertUtils.parseStringZ(br); } string g_PrologueText = ConvertUtils.parseStringZ(br); string g_PrologueTitle = ConvertUtils.parseStringZ(br); string g_PrologueSubTitle = ConvertUtils.parseStringZ(br); if (FileFormat == 25) { br.ReadBytes(4 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + 4); // int fog, int fog startz, int fog endz, int fogdensity, byte fogRED, byte ffogGREEN, byte fogBLUE, byte fogALPHA, int globalWeatherId ConvertUtils.parseStringZ(br); // custom sound environment br.ReadBytes(5); // bytes[5] {tilesetid, waterTintRED, waterTintGREEN, waterTintBLUE, waterTintALPHA} } int g_NumPlayers = MapNumPlayers = br.ReadInt32(); int ClosedSlots = 0; for (int i = 0; i < MapNumPlayers; i++) { Slot s = new Slot(); s.color = (byte)br.ReadInt32(); int status = br.ReadInt32(); if (status == 1) { s.slotStatus = (byte)SlotStatus.OPEN; } else if (status == 2) { s.slotStatus = (byte)SlotStatus.OCCUPIED; s.computer = 1; s.computertype = (byte)SlotCompType.NORMAL; } else { s.slotStatus = (byte)SlotStatus.CLOSED; ClosedSlots++; } switch (br.ReadInt32()) { case 1: s.race = (byte)SlotRace.HUMAN; break; case 2: s.race = (byte)SlotRace.ORC; break; case 3: s.race = (byte)SlotRace.UNDEAD; break; case 4: s.race = (byte)SlotRace.NIGHTELF; break; default: s.race = (byte)SlotRace.RANDOM; break; } br.ReadBytes(4); // fixedstart ConvertUtils.parseStringZ(br); //playername (could be interesting) br.ReadBytes(16); // startx, starty, allylow, allyhigh if (s.slotStatus != (byte)SlotStatus.CLOSED) { Slots.Add(s); } } MapNumPlayers -= ClosedSlots; int g_NumTeams = MapNumTeams = br.ReadInt32(); for (int i = 0; i < MapNumTeams; i++) { int Flags = br.ReadInt32(); int PlayerMask = br.ReadInt32(); for (int si = 0; si < MAX_SLOTS; si++) { if ((PlayerMask & 1) == 1) { foreach (Slot s in Slots) { if (s.color == si) { s.team = (byte)i; } } } PlayerMask >>= 1; } ConvertUtils.parseStringZ(br); //Team Name } } MapOptions = MapFlags & ((int)MAPOPTIONS.MELEE | (int)MAPOPTIONS.FIXEDPLAYERSETTINGS | (int)MAPOPTIONS.CUSTOMFORCES); MapFilterType = (int)MAPFILTERTYPE.SCENARIO; if ((MapOptions & (int)MAPOPTIONS.MELEE) == (int)MAPOPTIONS.MELEE) { byte team = 0; foreach (Slot s in Slots) { s.team = team++; s.race = (byte)SlotRace.RANDOM; } MapFilterType = (int)MAPFILTERTYPE.MELEE; } if ((MapOptions & (int)MAPOPTIONS.FIXEDPLAYERSETTINGS) != (int)MAPOPTIONS.FIXEDPLAYERSETTINGS) { foreach (Slot s in Slots) { s.race = (byte)(s.race | (byte)SlotRace.SELECTABLE); } } } } LoadGameVariables(); if ((MapFlags & (int)MAPFLAGS.RANDOMRACES) == (int)MAPFLAGS.RANDOMRACES) { foreach (Slot s in Slots) { s.race = (byte)SlotRace.RANDOM; } } if ((MapObservers & (int)MAPOBSERVERS.ALLOWED) == (int)MAPOBSERVERS.ALLOWED || (MapObservers & (int)MAPOBSERVERS.REFEREES) == (int)MAPOBSERVERS.REFEREES) { var observercount = MAX_SLOTS; if ((MapOptions & (int)MAPOPTIONS.MELEE) == (int)MAPOPTIONS.MELEE) { observercount = 12; } while (Slots.Count < observercount) { Slots.Add(new Slot(0, 255, (byte)SlotStatus.OPEN, 0, MAX_SLOTS, MAX_SLOTS, (byte)SlotRace.RANDOM | (byte)SlotRace.SELECTABLE)); } } // System.Console.WriteLine(BitConverter.ToString(MapInfo).Replace("-","")); // System.Console.WriteLine(BitConverter.ToString(MapCRC).Replace("-","")); // System.Console.WriteLine(BitConverter.ToString(MapSha).Replace("-","")); }
private void ExtractArchive() { using (MpqArchive archive = new MpqArchive(this.archiveFile)) { if ((this.destDir == null) || (this.destDir == "")) { this.destDir = Path.GetTempPath(); } archive.AddListfileFilenames(); if ((this.listFile != null) && (this.listFile != "")) { using (Stream stream = File.OpenRead(this.listFile)) { archive.AddFilenames(stream); } } byte[] buffer = new byte[0x40000]; if (!this.quietOutput) { Console.WriteLine("Extracting to {0}", this.destDir); } foreach (MpqEntry entry in (IEnumerable <MpqEntry>)archive) { if ((this.regex != null) && !this.regex.Match(entry.Filename).Success) { continue; } if (!this.quietOutput) { Console.Write(entry.Filename + " .. "); } string filename = entry.Filename; if (this.stripPath) { filename = Path.GetFileName(filename); } string path = Path.Combine(this.destDir, filename); string directoryName = Path.GetDirectoryName(path); this.CreateDirectory(directoryName); using (Stream stream2 = archive.OpenFile(entry)) { using (Stream stream3 = new FileStream(path, FileMode.Create)) { int num; Label_0135: num = stream2.Read(buffer, 0, buffer.Length); if (num != 0) { stream3.Write(buffer, 0, num); goto Label_0135; } stream3.Close(); } } if (!this.quietOutput) { Console.WriteLine("Done."); } } } }
/// <summary> /// Extracts files from the archive matching the pattern (if any) /// </summary> void ExtractArchive() { using(MpqArchive archive = new MpqArchive(archiveFile)) { // destination directory if(destDir == null || destDir == "") destDir = Directory.GetCurrentDirectory(); // default to current dir of not specified archive.AddListfileFilenames(); // setup external listfile if specified if (listFile != null && listFile != "") using (Stream s = File.OpenRead(listFile)) archive.AddFilenames(s); // buffers byte[] buf = new byte[0x40000]; if(!quietOutput) Console.WriteLine("Extracting to {0}", destDir); foreach(MpqEntry entry in archive) { // match pattern if (regex != null && !regex.Match(entry.Filename).Success) continue; if(!quietOutput) Console.Write(entry.Filename + " .. "); string srcFile = entry.Filename; if (stripPath) srcFile = Path.GetFileName(srcFile); // create destination directory string destFile = Path.Combine(destDir, srcFile); string absDestDir = Path.GetDirectoryName(destFile); CreateDirectory(absDestDir); // copy to destination file using(Stream stmIn = archive.OpenFile(entry)) { using(Stream stmOut = new FileStream(destFile, FileMode.Create)) { while(true) { int cb = stmIn.Read(buf, 0, buf.Length); if(cb == 0) break; stmOut.Write(buf, 0, cb); } stmOut.Close(); } } if(!quietOutput) Console.WriteLine("Done."); } } }
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); } }
/// <summary> /// Extracts files from the archive matching the pattern (if any) /// </summary> void ExtractArchive() { using (MpqArchive archive = new MpqArchive(archiveFile)) { // destination directory if (destDir == null || destDir == "") { destDir = Directory.GetCurrentDirectory(); // default to current dir of not specified } archive.AddListfileFilenames(); // setup external listfile if specified if (listFile != null && listFile != "") { using (Stream s = File.OpenRead(listFile)) archive.AddFilenames(s); } // buffers byte[] buf = new byte[0x40000]; if (!quietOutput) { Console.WriteLine("Extracting to {0}", destDir); } foreach (MpqEntry entry in archive) { // match pattern if (regex != null && !regex.Match(entry.Filename).Success) { continue; } if (!quietOutput) { Console.Write(entry.Filename + " .. "); } string srcFile = entry.Filename; if (stripPath) { srcFile = Path.GetFileName(srcFile); } // create destination directory string destFile = Path.Combine(destDir, srcFile); string absDestDir = Path.GetDirectoryName(destFile); CreateDirectory(absDestDir); // copy to destination file using (Stream stmIn = archive.OpenFile(entry)) { using (Stream stmOut = new FileStream(destFile, FileMode.Create)) { while (true) { int cb = stmIn.Read(buf, 0, buf.Length); if (cb == 0) { break; } stmOut.Write(buf, 0, cb); } stmOut.Close(); } } if (!quietOutput) { Console.WriteLine("Done."); } } } }
public static void ExtractCommand(string[] args) { var pmap = ConsoleManager.ParseCommand(args); string filter = ParamCheck <string>(pmap, "-f", false); string source = ParamCheck <string>(pmap, "-s"); string output = ParamCheck <string>(pmap, "-o"); SourceType sType = GetSourceType(source); if (string.IsNullOrWhiteSpace(filter)) { filter = "*"; } string regexfilter = "(" + Regex.Escape(filter).Replace(@"\*", @".*").Replace(@"\?", ".") + ")"; Func <string, bool> TypeCheck = t => Path.GetExtension(t).ToLower() == ".dbc" || Path.GetExtension(t).ToLower() == ".db2"; var dic = new ConcurrentDictionary <string, MemoryStream>(); switch (sType) { case SourceType.MPQ: Console.WriteLine("Loading from MPQ archive..."); using (MpqArchive archive = new MpqArchive(source, FileAccess.Read)) { string line = string.Empty; using (MpqFileStream listfile = archive.OpenFile("(listfile)")) using (StreamReader sr = new StreamReader(listfile)) { while ((line = sr.ReadLine()) != null) { if (TypeCheck(line) && Regex.IsMatch(line, regexfilter, RegexOptions.Compiled | RegexOptions.IgnoreCase)) { var ms = new MemoryStream(); archive.OpenFile(line).CopyTo(ms); dic.TryAdd(Path.GetFileName(line), ms); } } } } break; case SourceType.CASC: Console.WriteLine("Loading from CASC directory..."); using (var casc = new CASCHandler(source)) { var files = Constants.ClientDBFileNames.Where(x => Regex.IsMatch(Path.GetFileName(x), regexfilter, RegexOptions.Compiled | RegexOptions.IgnoreCase)); foreach (var file in files) { var stream = casc.ReadFile(file); if (stream != null) { dic.TryAdd(Path.GetFileName(file), stream); } } } break; } if (dic.Count == 0) { throw new Exception(" No matching files found."); } if (!Directory.Exists(output)) { Directory.CreateDirectory(output); } foreach (var d in dic) { using (var fs = new FileStream(Path.Combine(output, d.Key), FileMode.Create)) { fs.Write(d.Value.ToArray(), 0, (int)d.Value.Length); fs.Close(); } } dic.Clear(); Console.WriteLine($" Successfully extracted files."); Console.WriteLine(""); }
/// <summary> /// Loads a file into the console /// <para>load -f "*.dbc" -s ".mpq/wow dir" -b 11802</para> /// </summary> /// <param name="args"></param> /// public static void LoadCommand(string[] args) { var pmap = ConsoleManager.ParseCommand(args); string file = ParamCheck <string>(pmap, "-f"); string filename = Path.GetFileName(file); string filenoext = Path.GetFileNameWithoutExtension(file); string source = ParamCheck <string>(pmap, "-s", false); int build = ParamCheck <int>(pmap, "-b"); SourceType sType = GetSourceType(source); //Check file exists if loaded from the filesystem if (!File.Exists(file) && sType == SourceType.File) { throw new Exception($" File not found {file}."); } //Check the required definition exists var def = Database.Definitions.Tables.FirstOrDefault(x => x.Build == build && x.Name.Equals(filenoext, IGNORECASE)); if (def == null) { throw new Exception($" Could not find definition for {Path.GetFileName(file)} build {build}."); } Database.BuildNumber = build; var dic = new ConcurrentDictionary <string, MemoryStream>(); string error = string.Empty; switch (sType) { case SourceType.MPQ: Console.WriteLine("Loading from MPQ archive..."); using (MpqArchive archive = new MpqArchive(source, FileAccess.Read)) { string line = string.Empty; bool loop = true; using (MpqFileStream listfile = archive.OpenFile("(listfile)")) using (StreamReader sr = new StreamReader(listfile)) { while ((line = sr.ReadLine()) != null && loop) { if (line.EndsWith(filename, IGNORECASE)) { loop = false; var ms = new MemoryStream(); archive.OpenFile(line).CopyTo(ms); dic.TryAdd(filename, ms); error = Database.LoadFiles(dic).Result.FirstOrDefault(); } } } } break; case SourceType.CASC: Console.WriteLine("Loading from CASC directory..."); using (var casc = new CASCHandler(source)) { string fullname = filename; if (!fullname.StartsWith("DBFilesClient", IGNORECASE)) { fullname = "DBFilesClient\\" + filename; //Ensure we have the current file name structure } var stream = casc.ReadFile(fullname); if (stream != null) { dic.TryAdd(filename, stream); error = Database.LoadFiles(dic).Result.FirstOrDefault(); } } break; default: error = Database.LoadFiles(new string[] { file }).Result.FirstOrDefault(); break; } dic.Clear(); if (!string.IsNullOrWhiteSpace(error)) { throw new Exception(" " + error); } if (Database.Entries.Count == 0) { throw new Exception(" File could not be loaded."); } Console.WriteLine($"{Path.GetFileName(file)} loaded."); Console.WriteLine(""); }
/// <exception cref="ArgumentException">Thrown when the <see cref="MpqArchive"/> does not contain an <see cref="Attributes"/> file.</exception> public static bool VerifyAttributes(this MpqArchive archive) { if (!archive.TryOpenFile(Attributes.FileName, out var attributesStream)) { throw new ArgumentException($"The archive must contain an {Attributes.FileName} file.", nameof(archive)); } archive.AddFileName(Signature.FileName); using var reader = new BinaryReader(attributesStream); var attributes = reader.ReadAttributes(); var hasCrc32 = attributes.Flags.HasFlag(AttributesFlags.Crc32); var hasDateTime = attributes.Flags.HasFlag(AttributesFlags.DateTime); var hasUnk0x04 = attributes.Flags.HasFlag(AttributesFlags.Unk0x04); var count = 0; foreach (var mpqEntry in archive) { if (hasCrc32) { var actualCrc32 = attributes.Crc32s[count]; if (string.Equals(mpqEntry.FileName, Attributes.FileName, StringComparison.OrdinalIgnoreCase)) { if (actualCrc32 != 0) { return(false); } } else if (string.Equals(mpqEntry.FileName, Signature.FileName, StringComparison.OrdinalIgnoreCase)) { if (actualCrc32 != _signatureCrc32) { return(false); } } else { using var mpqEntryStream = archive.OpenFile(mpqEntry); if (actualCrc32 != new CRC32().GetCrc32(mpqEntryStream)) { return(false); } } } if (hasUnk0x04) { var unk0x04 = attributes.Unk0x04s[count]; if (unk0x04.Length != 16) { return(false); } for (var i = 0; i < 16; i++) { if (unk0x04[i] != 0) { return(false); } } } count++; } return((!hasCrc32 || attributes.Crc32s.Count == count) && (!hasDateTime || attributes.DateTimes.Count == count) && (!hasUnk0x04 || attributes.Unk0x04s.Count == count)); }
private static void OpenArchiveBackgroundWork(object?sender, DoWorkEventArgs e) { _archive = MpqArchive.Open((string)e.Argument, true); _archive.DiscoverFileNames(); var mapsList = new HashSet <string>(); if (_archive.IsCampaignArchive(out var campaignInfo)) { for (var i = 0; i < campaignInfo.Maps.Count; i++) { mapsList.Add(campaignInfo.Maps[i].MapFilePath); } } else { using var mpqStream = _archive.OpenFile(MapInfo.FileName); using var reader = new BinaryReader(mpqStream); _originPatch = reader.ReadMapInfo().GetOriginGamePatch(); } var listViewItems = new List <ListViewItem>(); var possibleOriginPatches = new HashSet <GamePatch>(); var files = _archive.ToList(); var progress = new OpenArchiveProgress(); progress.Maximum = files.Count; foreach (var file in files) { if (mapsList.Contains(file.FileName)) { var mapName = file.FileName; using var mapArchiveStream = _archive.OpenFile(mapName); using var mapArchive = MpqArchive.Open(mapArchiveStream, true); mapArchive.DiscoverFileNames(); var children = new List <ListViewItem>(); var mapFiles = mapArchive.ToList(); progress.Maximum += mapFiles.Count; foreach (var mapFile in mapArchive) { var subItem = ListViewItemExtensions.Create(new ItemTag(mapArchive, mapFile, mapName)); subItem.IndentCount = 1; children.Add(subItem); _openArchiveWorker.ReportProgress(0, progress); } using (var mapInfoFileStream = mapArchive.OpenFile(MapInfo.FileName)) { using var reader = new BinaryReader(mapInfoFileStream); var mapArchiveOriginPatch = reader.ReadMapInfo().GetOriginGamePatch(); var mapArchiveItem = ListViewItemExtensions.Create(new ItemTag(_archive, file, children.ToArray(), mapArchiveOriginPatch)); listViewItems.Add(mapArchiveItem); _openArchiveWorker.ReportProgress(0, progress); if (mapArchiveOriginPatch.HasValue) { possibleOriginPatches.Add(mapArchiveOriginPatch.Value); } } foreach (var child in children) { listViewItems.Add(child); } } else { var item = ListViewItemExtensions.Create(new ItemTag(_archive, file)); listViewItems.Add(item); _openArchiveWorker.ReportProgress(0, progress); } } if (_originPatch is null) { _originPatch = possibleOriginPatches.Count == 1 ? possibleOriginPatches.Single() : _latestPatch; } e.Result = listViewItems; }
private static void SaveArchiveBackgroundWork(object?sender, DoWorkEventArgs e) { var archiveBuilder = new MpqArchiveBuilder(_archive); var progress = new SaveArchiveProgress(); progress.Saving = false; for (var i = 0; i < _fileList.Items.Count; i++) { var tag = _fileList.Items[i].GetTag(); if (tag.Parent is not null) { continue; } if (tag.Status == MapFileStatus.Removed) { if (tag.TryGetHashedFileName(out var hashedFileName)) { archiveBuilder.RemoveFile(hashedFileName); } else { archiveBuilder.RemoveFile(_archive, tag.MpqEntry); } } else if (tag.Children is not null) { if (tag.Children.All(child => child.Status == MapFileStatus.Removed)) { throw new InvalidOperationException("Parent tag should have been removed since all child tags are removed, but was " + tag.Status); } else if (tag.Children.Any(child => child.IsModified || child.Status == MapFileStatus.Removed)) { // Assume at most one nested archive (for campaign archives), so no recursion. using var subArchive = MpqArchive.Open(_archive.OpenFile(tag.FileName)); foreach (var child in tag.Children) { if (child.FileName != null) { subArchive.AddFileName(child.FileName); } } var subArchiveBuilder = new MpqArchiveBuilder(subArchive); foreach (var child in tag.Children) { if (child.Status == MapFileStatus.Removed) { if (child.TryGetHashedFileName(out var hashedFileName)) { subArchiveBuilder.RemoveFile(hashedFileName); } else { subArchiveBuilder.RemoveFile(subArchive, child.MpqEntry); } } else if (child.TryGetModifiedMpqFile(out var subArchiveAdaptedFile)) { subArchiveBuilder.AddFile(subArchiveAdaptedFile); _saveArchiveWorker.ReportProgress(0, progress); } else { _saveArchiveWorker.ReportProgress(0, progress); } } var adaptedSubArchiveStream = new MemoryStream(); subArchiveBuilder.SaveWithPreArchiveData(adaptedSubArchiveStream, true); adaptedSubArchiveStream.Position = 0; var adaptedFile = MpqFile.New(adaptedSubArchiveStream, tag.FileName, false); adaptedFile.TargetFlags = tag.MpqEntry.Flags; archiveBuilder.AddFile(adaptedFile); _saveArchiveWorker.ReportProgress(0, progress); } else { _saveArchiveWorker.ReportProgress(tag.Children.Length, progress); } } else if (tag.TryGetModifiedMpqFile(out var adaptedFile)) { archiveBuilder.AddFile(adaptedFile); _saveArchiveWorker.ReportProgress(0, progress); } else { _saveArchiveWorker.ReportProgress(0, progress); } } progress.Saving = true; _saveArchiveWorker.ReportProgress(0, progress); using (var fileStream = File.Create((string)e.Argument)) { archiveBuilder.SaveWithPreArchiveData(fileStream); } }
public void ProcessMPQ(List <string> lstAllMPQFiles) { // Create a folder to dump all this into Directory.CreateDirectory(DBCOutputDir); // Go through all the files, getting all DBCs foreach (var mpqFileName in lstAllMPQFiles) { //Directory.CreateDirectory(Path.Combine(DBCOutputDir, Path.GetFileNameWithoutExtension(mpqFileName))); using (var oArchive = new MpqArchive(mpqFileName)) { var dbcFiles = oArchive.FindAllFiles("*.dbc"); //var dbcsFiles = from a in oArchive.Files // where a.Name.EndsWith(".dbc") // select a.Name; foreach (var strFileName in dbcFiles) { var strLocalFilePath = string.Format(@"{0}\{1}", DBCOutputDir, Path.GetFileName(strFileName)); //var strLocalFilePath = Path.Combine(DBCOutputDir, Path.GetFileNameWithoutExtension(mpqFileName)); //strLocalFilePath = Path.Combine(strLocalFilePath, Path.GetFileName(strFileName)); if (File.Exists(strLocalFilePath)) { continue; } using (Stream stmOutput = new FileStream(strLocalFilePath, FileMode.Create)) { using (Stream stmInput = oArchive.OpenFile(strFileName).GetStream()) { // Writing... Console.Write(string.Format("Writing File {0}....", Path.GetFileName(strFileName))); // Create an 8kb buffer var byFileContents = new byte[8192]; // Loop until we're out of data while (true) { // Read from the MPQ int intBytesRead = stmInput.Read(byFileContents, 0, byFileContents.Length); // Was there anything to read? if (intBytesRead == 0) { break; } // Write to the file stmOutput.Write(byFileContents, 0, intBytesRead); } } Console.WriteLine("Done"); } } } } }
public static bool ExtractDBC() { try { Console.WriteLine("Extracting DBC files..."); //Check if dbc.MPQ exist. if (!File.Exists(Globals.DBCPath)) { Console.WriteLine($"Unable to locate dbc.MPQ at path {Globals.DBCPath}, please check Config.txt and set a proper installation path."); return(false); } // Clean up output directory if neccesary. if (Directory.Exists(OutputPath)) { Directory.Delete(OutputPath, true); } Directory.CreateDirectory(OutputPath); using (MpqArchive archive = new MpqArchive(Globals.DBCPath)) { archive.AddListfileFilenames(); foreach (var entry in archive) { if (!string.IsNullOrEmpty(entry.Filename)) { var outputFileName = Path.Combine(OutputPath, Path.GetFileName(entry.Filename)); if (File.Exists(outputFileName)) { File.Delete(outputFileName); } if (entry.Filename.Equals("DBFilesClient\\AreaTable.dbc")) { byte[] buf = new byte[0x40000]; using (Stream streamIn = archive.OpenFile(entry)) { using (Stream streamOut = new FileStream(outputFileName, FileMode.Create)) { while (true) { int cb = streamIn.Read(buf, 0, buf.Length); if (cb == 0) { break; } streamOut.Write(buf, 0, cb); Program.UpdateLoadingStatus(); } streamOut.Close(); } } Console.WriteLine($"Extracted DBC file {entry.Filename}"); } } } } return(true); } catch (Exception ex) { Console.WriteLine(ex.Message); } return(false); }