/// <summary> /// Loads a cache file from a stream. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="engineDb">The engine database to use to process the cache file.</param> /// <param name="engineInfo">On output, this will contain the cache file's engine description.</param> /// <returns>The cache file that was loaded.</returns> /// <exception cref="ArgumentException">Thrown if the cache file is invalid.</exception> /// <exception cref="NotSupportedException">Thrown if the cache file's target engine is not supported.</exception> public static ICacheFile LoadCacheFile(IReader reader, EngineDatabase engineDb, out EngineDescription engineInfo) { // Set the reader's endianness based upon the file's header magic reader.SeekTo(0); byte[] headerMagic = reader.ReadBlock(4); reader.Endianness = DetermineCacheFileEndianness(headerMagic); // Load engine version info var version = new CacheFileVersionInfo(reader); if (version.Engine != EngineType.SecondGeneration && version.Engine != EngineType.ThirdGeneration) { throw new NotSupportedException("Engine not supported"); } // Load build info engineInfo = engineDb.FindEngineByVersion(version.BuildString); if (engineInfo == null) { throw new NotSupportedException("Engine version \"" + version.BuildString + "\" not supported"); } // Load the cache file depending upon the engine version switch (version.Engine) { case EngineType.SecondGeneration: return(new SecondGenCacheFile(reader, engineInfo, version.BuildString)); case EngineType.ThirdGeneration: return(new ThirdGenCacheFile(reader, engineInfo, version.BuildString)); default: throw new NotSupportedException("Engine not supported"); } }
/// <summary> /// Loads a cache file from a stream. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="engineDb">The engine database to use to process the cache file.</param> /// <param name="engineInfo">On output, this will contain the cache file's engine description.</param> /// <returns>The cache file that was loaded.</returns> /// <exception cref="ArgumentException">Thrown if the cache file is invalid.</exception> /// <exception cref="NotSupportedException">Thrown if the cache file's target engine is not supported.</exception> public static ICacheFile LoadCacheFile(IReader reader, EngineDatabase engineDb, out EngineDescription engineInfo) { // Set the reader's endianness based upon the file's header magic reader.SeekTo(0); byte[] headerMagic = reader.ReadBlock(4); reader.Endianness = DetermineCacheFileEndianness(headerMagic); // Load engine version info var version = new CacheFileVersionInfo(reader); if (version.Engine != EngineType.SecondGeneration && version.Engine != EngineType.ThirdGeneration) throw new NotSupportedException("Engine not supported"); // Load build info engineInfo = engineDb.FindEngineByVersion(version.BuildString); if (engineInfo == null) throw new NotSupportedException("Engine version \"" + version.BuildString + "\" not supported"); // Load the cache file depending upon the engine version switch (version.Engine) { case EngineType.SecondGeneration: return new SecondGenCacheFile(reader, engineInfo, version.BuildString); case EngineType.ThirdGeneration: return new ThirdGenCacheFile(reader, engineInfo, version.BuildString); default: throw new NotSupportedException("Engine not supported"); } }
/// <summary> /// Loads a cache file from a stream. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="engineDb">The engine database to use to process the cache file.</param> /// <param name="engineInfo">On output, this will contain the cache file's engine description.</param> /// <returns>The cache file that was loaded.</returns> /// <exception cref="ArgumentException">Thrown if the cache file is invalid.</exception> /// <exception cref="NotSupportedException">Thrown if the cache file's target engine is not supported.</exception> public static ICacheFile LoadCacheFile(IReader map_reader, IReader tag_reader, IReader string_reader, out string tagnamesLocation, string filesLocation, EngineDatabase engineDb, out EngineDescription engineInfo) { // Set the reader's endianness based upon the file's header magic map_reader.SeekTo(0); byte[] headerMagic = map_reader.ReadBlock(4); Endian engianess = DetermineCacheFileEndianness(headerMagic); map_reader.Endianness = engianess; if(tag_reader != null) tag_reader.Endianness = engianess; if (tag_reader != null) string_reader.Endianness = engianess; // Load engine version info var version = new CacheFileVersionInfo(map_reader); if (version.Engine != EngineType.SecondGeneration && version.Engine != EngineType.ThirdGeneration && version.Engine != EngineType.FourthGeneration) throw new NotSupportedException("Engine not supported"); // Load build info engineInfo = engineDb.FindEngineByVersion(version.BuildString); if (engineInfo == null) throw new NotSupportedException("Engine version \"" + version.BuildString + "\" not supported"); // Load the cache file depending upon the engine version switch (version.Engine) { case EngineType.SecondGeneration: tagnamesLocation = null; return new SecondGenCacheFile(map_reader, engineInfo, version.BuildString); case EngineType.ThirdGeneration: tagnamesLocation = null; return new ThirdGenCacheFile(map_reader, engineInfo, version.BuildString); case EngineType.FourthGeneration: if (tag_reader == null || tag_reader.BaseStream.Length == 0) throw new Exception("Can't load version 4 cache file without tags file. Please make sure that tags.dat is in the same folder at the map file."); if (string_reader == null || tag_reader.BaseStream.Length == 0) throw new Exception("Can't load version 4 cache file without strings file. Please make sure that tags.dat is in the same folder at the map file."); // Load the tag names csv file string tagnames_filename = "tagnames_" + version.BuildString + ".csv"; string tagnames_location = filesLocation != null ? filesLocation + tagnames_filename : ""; if (!File.Exists(tagnames_location)) tagnames_location = "tagnames\\" + tagnames_filename; if (!File.Exists(tagnames_location)) tagnames_location = null; FileStream tagnamesFileStream = tagnames_location != null ? TryInitFilestream(tagnames_location) : null; EndianReader tagnames_reader = null; if (tagnamesFileStream != null) { tagnames_reader = new EndianReader(tagnamesFileStream, Endian.BigEndian); tagnames_reader.Endianness = engianess; } tagnamesLocation = tagnames_location; FourthGenCacheFile cache_file = new FourthGenCacheFile(map_reader, tag_reader, string_reader, tagnames_reader, engineInfo, version.BuildString); tagnamesFileStream.Close(); return cache_file; default: throw new NotSupportedException("Engine not supported"); } }
private void btnCreatePatchModifiedMap_Click(object sender, RoutedEventArgs e) { var ofd = new OpenFileDialog { Title = "Assembly - Select a Modified Map file", Filter = "Blam Cache Files|*.map" }; if (ofd.ShowDialog() != DialogResult.OK) return; txtCreatePatchModifiedMap.Text = ofd.FileName; txtCreatePatchOutputName.Text = Path.GetFileNameWithoutExtension(ofd.FileName); var fileStream = new FileStream(ofd.FileName, FileMode.Open); var cacheStream = new EndianStream(fileStream, Endian.BigEndian); var versionInfo = new CacheFileVersionInfo(cacheStream); var engine = App.AssemblyStorage.AssemblySettings.DefaultDatabase.FindEngineByVersion(versionInfo.BuildString); if (engine != null && engine.Name != null) { switch (engine.Name) { case "Halo 2 Vista": cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo2Vista; break; case "Halo 3: ODST": cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo3ODST; break; default: if (engine.Name.Contains("Halo 3")) cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo3; else if (engine.Name.Contains("Halo: Reach")) cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.HaloReach; else if (engine.Name.Contains("Halo 4")) cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo4; else cboxCreatePatchTargetGame.SelectedIndex = 5; // Other break; } } cacheStream.Close(); }
private KeyValuePair<ICacheFile, EngineDescription> LoadMap(string path, out IReader reader) { reader = new EndianReader(File.OpenRead(path), Endian.BigEndian); var versionInfo = new CacheFileVersionInfo(reader); EngineDescription buildInfo = App.AssemblyStorage.AssemblySettings.DefaultDatabase.FindEngineByVersion(versionInfo.BuildString); return new KeyValuePair<ICacheFile, EngineDescription>(new ThirdGenCacheFile(reader, buildInfo, versionInfo.BuildString), buildInfo); }
private static void Main(string[] args) { if (args.Length != 3) { Console.WriteLine("Usage: mapexpand <map file> <section> <page count>"); Console.WriteLine(); Console.WriteLine("Available sections:"); Console.WriteLine(" stringidindex"); Console.WriteLine(" stringiddata"); Console.WriteLine(" tagnameindex"); Console.WriteLine(" tagnamedata"); Console.WriteLine(" resource"); Console.WriteLine(" tag"); return; } int pageCount; if (!int.TryParse(args[2], out pageCount) || pageCount <= 0) { Console.WriteLine("The page count must be a positive integer."); return; } Console.WriteLine("Reading..."); var stream = new EndianStream(File.Open(args[0], FileMode.Open, FileAccess.ReadWrite), Endian.BigEndian); var version = new CacheFileVersionInfo(stream); if (version.Engine != EngineType.ThirdGeneration) { Console.WriteLine("Only third-generation map files are supported."); return; } var database = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml"); var buildInfo = database.FindEngineByVersion(version.BuildString); var cacheFile = new ThirdGenCacheFile(stream, buildInfo, version.BuildString); FileSegmentGroup area; FileSegment section; int pageSize; switch (args[1]) { case "stringidindex": area = cacheFile.StringArea; section = cacheFile.StringIDIndexTable; pageSize = 0x1000; break; case "stringiddata": area = cacheFile.StringArea; section = cacheFile.StringIDDataTable; pageSize = 0x1000; break; case "tagnameindex": area = cacheFile.StringArea; section = cacheFile.FileNameIndexTable; pageSize = 0x1000; break; case "tagnamedata": area = cacheFile.StringArea; section = cacheFile.FileNameDataTable; pageSize = 0x1000; break; case "resource": area = null; section = cacheFile.RawTable; pageSize = 0x1000; break; case "tag": area = cacheFile.MetaArea; section = cacheFile.MetaArea.Segments[0]; pageSize = 0x10000; break; default: Console.WriteLine("Invalid section name: \"{0}\"", args[1]); return; } Console.WriteLine("- Engine version: {0}", version.BuildString); Console.WriteLine("- Internal name: {0}", cacheFile.InternalName); Console.WriteLine("- Scenario name: {0}", cacheFile.ScenarioName); Console.WriteLine(); Console.WriteLine("Injecting empty pages..."); var injectSize = pageCount * pageSize; section.Resize(section.Size + injectSize, stream); Console.WriteLine("Adjusting the header..."); cacheFile.SaveChanges(stream); stream.Close(); Console.WriteLine(); var offset = section.Offset; if (section.ResizeOrigin == SegmentResizeOrigin.End) offset += section.ActualSize - injectSize; if (area != null) Console.WriteLine("Successfully injected 0x{0:X} bytes at 0x{1:X} (offset 0x{2:X}).", injectSize, area.BasePointer, offset); else Console.WriteLine("Successfully injected 0x{0:X} bytes at offset 0x{1:X}.", injectSize, offset); }
static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: mapexpand <map file> <page count>"); Console.WriteLine("Pages are multiples of 0x10000 bytes."); return; } int pageCount; if (!int.TryParse(args[1], out pageCount) || pageCount <= 0) { Console.WriteLine("The page count must be a positive integer."); return; } Console.WriteLine("Reading..."); EndianStream stream = new EndianStream(File.Open(args[0], FileMode.Open, FileAccess.ReadWrite), Endian.BigEndian); CacheFileVersionInfo version = new CacheFileVersionInfo(stream); if (version.Engine != EngineType.ThirdGeneration) { Console.WriteLine("Only third-generation map files are supported."); return; } BuildInfoLoader infoLoader = new BuildInfoLoader(XDocument.Load("Formats/SupportedBuilds.xml"), "Formats/"); BuildInformation buildInfo = infoLoader.LoadBuild(version.BuildString); ThirdGenCacheFile cacheFile = new ThirdGenCacheFile(stream, buildInfo, version.BuildString); Console.WriteLine("- Engine version: {0}", version.BuildString); Console.WriteLine("- Internal name: {0}", cacheFile.InternalName); Console.WriteLine("- Scenario name: {0}", cacheFile.ScenarioName); Console.WriteLine("- File size: 0x{0:X}", cacheFile.FileSize); Console.WriteLine("- Virtual size: 0x{0:X}", cacheFile.MetaArea.Size); for (int i = 0; i < cacheFile.Partitions.Length; i++) { var partition = cacheFile.Partitions[i]; if (partition.BasePointer != null) Console.WriteLine(" - Partition {0} at 0x{1:X}-0x{2:X} (size=0x{3:X})", i, partition.BasePointer.AsPointer(), partition.BasePointer.AsPointer() + partition.Size - 1, partition.Size); } Console.WriteLine("- Meta pointer mask: 0x{0:X}", cacheFile.MetaArea.PointerMask); Console.WriteLine("- Locale pointer mask: 0x{0:X}", (uint)-cacheFile.LocaleArea.PointerMask); Console.WriteLine("- String pointer mask: 0x{0:X}", cacheFile.StringArea.PointerMask); Console.WriteLine(); Console.WriteLine("Injecting empty pages..."); int injectSize = pageCount * 0x10000; Console.WriteLine("- Start address: 0x{0:X} (offset 0x{1:X})", cacheFile.MetaArea.BasePointer - injectSize, cacheFile.MetaArea.Offset); cacheFile.MetaArea.Resize(cacheFile.MetaArea.Size + injectSize, stream); Console.WriteLine(); Console.WriteLine("Adjusting the header..."); cacheFile.SaveChanges(stream); Console.WriteLine(); Console.WriteLine("Successfully injected 0x{0:X} bytes at 0x{1:X} (offset 0x{2:X}).", injectSize, cacheFile.MetaArea.BasePointer, cacheFile.MetaArea.Offset); stream.Close(); }
/// <summary> /// Loads a cache file from a stream. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="engineDb">The engine database to use to process the cache file.</param> /// <param name="engineInfo">On output, this will contain the cache file's engine description.</param> /// <returns>The cache file that was loaded.</returns> /// <exception cref="ArgumentException">Thrown if the cache file is invalid.</exception> /// <exception cref="NotSupportedException">Thrown if the cache file's target engine is not supported.</exception> public static ICacheFile LoadCacheFile(IReader map_reader, IReader tag_reader, IReader string_reader, out string tagnamesLocation, string filesLocation, EngineDatabase engineDb, out EngineDescription engineInfo, string tagsLocation, string stringsLocation) { // Set the reader's endianness based upon the file's header magic map_reader.SeekTo(0); byte[] headerMagic = map_reader.ReadBlock(4); Endian engianess = DetermineCacheFileEndianness(headerMagic); map_reader.Endianness = engianess; if (tag_reader != null) { tag_reader.Endianness = engianess; } if (tag_reader != null) { string_reader.Endianness = engianess; } // Load engine version info var version = new CacheFileVersionInfo(map_reader); if (version.Engine == EngineType.FirstGeneration) { throw new NotSupportedException("Engine not supported"); } // Load build info engineInfo = engineDb.FindEngineByVersion(version.BuildString); if (engineInfo == null) { throw new NotSupportedException("Engine version \"" + version.BuildString + "\" not supported"); } // Load the cache file depending upon the engine version switch (version.Engine) { case EngineType.SecondGeneration: tagnamesLocation = null; return(new SecondGenCacheFile(map_reader, engineInfo, version.BuildString)); case EngineType.ThirdGeneration: tagnamesLocation = null; return(new ThirdGenCacheFile(map_reader, engineInfo, version.BuildString)); case EngineType.ThirdGenMCC: tagnamesLocation = null; return(new NewThirdGenCacheFile(map_reader, engineInfo, version.BuildString)); case EngineType.FourthGeneration: if (tag_reader == null || tag_reader.BaseStream.Length == 0) { throw new Exception("Can't load version 4 cache file without tags file. Please make sure that tags.dat is in the same folder at the map file."); } if (string_reader == null || tag_reader.BaseStream.Length == 0) { throw new Exception("Can't load version 4 cache file without strings file. Please make sure that tags.dat is in the same folder at the map file."); } string tagnames_location = Path.Combine(Path.GetDirectoryName(tagsLocation), "tag_list.csv"); if (!File.Exists(tagnames_location)) { tagnames_location = null; } if (tagnames_location == null) { // Load the tag names csv file string tagnames_filename = "tagnames_"; if (engineInfo.AltTagNames != null) { tagnames_filename += engineInfo.AltTagNames + ".csv"; } else { tagnames_filename += version.BuildString + ".csv"; } tagnames_location = filesLocation != null ? filesLocation + tagnames_filename : ""; if (File.Exists(tagnames_location)) { tagnames_location = "tagnames\\" + tagnames_filename; } else { tagnames_location = null; } } FileStream tagnamesFileStream = tagnames_location != null?TryInitFilestream(tagnames_location) : null; EndianReader tagnames_reader = null; if (tagnamesFileStream != null) { tagnames_reader = new EndianReader(tagnamesFileStream, Endian.BigEndian); tagnames_reader.Endianness = engianess; } tagnamesLocation = tagnames_location; FourthGenCacheFile cache_file = new FourthGenCacheFile(map_reader, tag_reader, string_reader, tagnames_reader, engineInfo, version.BuildString); tagnamesFileStream.Close(); return(cache_file); default: throw new NotSupportedException("Engine not supported"); } }
private KeyValuePair<ICacheFile, BuildInformation> LoadMap(string path, out IReader reader) { reader = new EndianReader(File.OpenRead(path), Endian.BigEndian); var versionInfo = new CacheFileVersionInfo(reader); var buildInfo = _buildLoader.LoadBuild(versionInfo.BuildString); return new KeyValuePair<ICacheFile, BuildInformation>(new ThirdGenCacheFile(reader, buildInfo, versionInfo.BuildString), buildInfo); }