private static CompressionState DetermineState(IReader reader, EngineDatabase engineDb, out EngineType type) { // Set the reader's endianness based upon the file's header magic reader.SeekTo(0); byte[] headerMagic = reader.ReadBlock(4); reader.Endianness = CacheFileLoader.DetermineCacheFileEndianness(headerMagic); // Load engine version info var version = new CacheFileVersionInfo(reader); type = version.Engine; if (version.Engine == EngineType.SecondGeneration) { // Load build info var engineInfo = engineDb.FindEngineByVersion(version.BuildString); if (engineInfo == null) { return(CompressionState.Null); } if (!engineInfo.UsesCompression) { return(CompressionState.Null); } return(AnalyzeSecondGen(reader, engineInfo)); } else { return(CompressionState.Null); } }
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 KeyValuePair <ICacheFile, EngineDescription> LoadMap(string path, out IReader reader) { reader = new EndianReader(File.OpenRead(path), Endian.BigEndian); reader.SeekTo(0); byte[] headerMagic = reader.ReadBlock(4); reader.Endianness = CacheFileLoader.DetermineCacheFileEndianness(headerMagic); var versionInfo = new CacheFileVersionInfo(reader); EngineDescription buildInfo = App.AssemblyStorage.AssemblySettings.DefaultDatabase.FindEngineByVersion(versionInfo.BuildString); return (new KeyValuePair <ICacheFile, EngineDescription>(new ThirdGenCacheFile(reader, buildInfo, path, versionInfo.BuildString), buildInfo)); }
public BlamCacheFile(string filePath) { if (!File.Exists(filePath)) { throw new FileNotFoundException("Invalid cache file path"); } fileStream = new EndianStream(File.Open(filePath, FileMode.Open, FileAccess.ReadWrite), Endian.LittleEndian); cacheFileVersion = new CacheFileVersionInfo(fileStream); EngineDatabase database = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml"); buildInfo = database.FindEngineByVersion(cacheFileVersion.BuildString); switch (cacheFileVersion.Engine) { case EngineType.ThirdGeneration: internalCacheFile = CreateThirdGenCacheFile(fileStream, buildInfo, cacheFileVersion); break; default: throw new InvalidOperationException("Only third generation engine map files are supported at the moment!"); } }
private static ICacheFile CreateThirdGenCacheFile(IReader inputReader, EngineDescription buildInfo, CacheFileVersionInfo cacheFileVersion) { string buildString = cacheFileVersion.BuildString; return(new ThirdGenCacheFile(inputReader, buildInfo, buildString)); }
// TODO (Dragon): support CEA 360 with LZX private static CompressionState DetermineState(IReader reader, EngineDatabase engineDb, out EngineType type, out EngineDescription engineInfo) { CacheFileVersionInfo version = null; // not all compressed maps have a decompressed header // so we handle that here try { // Attempt to set the reader's endianness based upon the file's header magic reader.SeekTo(0); byte[] headerMagic = reader.ReadBlock(4); reader.Endianness = CacheFileLoader.DetermineCacheFileEndianness(headerMagic); // Load engine version info version = new CacheFileVersionInfo(reader); } catch (ArgumentException e) // map had no header, assume its CEA { using (MemoryStream ms_header_out = new MemoryStream()) { // first chunk offset is at 0x4 reader.SeekTo(0x4); int first_chunk_offset = reader.ReadInt32(); int second_chunk_offset = reader.ReadInt32(); int first_chunk_size = second_chunk_offset - first_chunk_offset - 6; reader.SeekTo(first_chunk_offset); // CEA 360 stores an 0xFF, use it for ID byte cea_360_ff_byte = reader.ReadByte(); if (cea_360_ff_byte == 0xFF) // CEA 360 { // TODO (Dragon): decompress first chunk to get the header with lzx throw new InvalidOperationException("assembly does not support CEA 360 decompression (missing LZX)"); } else // assume CEA MCC { reader.SeekTo(first_chunk_offset + 6); byte[] first_chunk_bytes = reader.ReadBlock(first_chunk_size); using (MemoryStream ms_header_comp = new MemoryStream(first_chunk_bytes)) { //ms_header_comp.Write(first_chunk_bytes, 0, first_chunk_size); using (DeflateStream ds = new DeflateStream(ms_header_comp, CompressionMode.Decompress)) { ds.CopyTo(ms_header_out); } } } EndianReader header_reader = new EndianReader(ms_header_out, Endian.LittleEndian); version = new CacheFileVersionInfo(header_reader); } } // if version wasnt set its because we couldnt read a proper header, throw an exception if (version == null) { throw new NullReferenceException("Failed to create CacheFileVersionInfo from map header"); } type = version.Engine; engineInfo = engineDb.FindEngineByVersion(version.BuildString); if (version.Engine == EngineType.FirstGeneration) { if (engineInfo == null) { return(CompressionState.Null); } if (!engineInfo.UsesCompression) { return(CompressionState.Null); } return(AnalyzeFirstGen(reader, engineInfo)); } else if (version.Engine == EngineType.SecondGeneration) { if (engineInfo == null) { return(CompressionState.Null); } if (!engineInfo.UsesCompression) { return(CompressionState.Null); } return(AnalyzeSecondGen(reader, engineInfo)); } else { return(CompressionState.Null); } }
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.Dispose(); 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); } }