// TODO (Dragon): support CEA 360 with LZX private static CompressionState DetermineState(IReader reader, EngineDatabase engineDb, out EngineDescription engineInfo, out StructureValueCollection headerValues) { headerValues = null; // not all compressed maps have a decompressed header // so we handle that here try { // Load engine version info engineInfo = CacheFileLoader.FindEngineDescription(reader, engineDb); } 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); engineInfo = CacheFileLoader.FindEngineDescription(header_reader, engineDb); } } // if engine wasnt set its because we couldnt read a proper header, throw an exception if (engineInfo == null || !engineInfo.UsesCompression) { return(CompressionState.Null); } if (engineInfo.Engine == EngineType.FirstGeneration) { return(AnalyzeFirstGen(reader, engineInfo, out headerValues)); } else if (engineInfo.Engine == EngineType.SecondGeneration) { return(AnalyzeSecondGen(reader, engineInfo, out headerValues)); } 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); byte[] headerMagic = new byte[4]; fileStream.Read(headerMagic, 0, 4); var cacheStream = new EndianStream(fileStream, Endian.BigEndian); _buildInfo = CacheFileLoader.FindEngineDescription(cacheStream, App.AssemblyStorage.AssemblySettings.DefaultDatabase); if (_buildInfo != null && _buildInfo.Name != null) { switch (_buildInfo.Name) { case "Halo 2 Vista": cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo2Vista; break; case "Halo 3: ODST": cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo3ODST; break; default: if (_buildInfo.Name.Contains("MCC")) { cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.MCC; } else if (_buildInfo.Name.Contains("Halo 3")) { cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo3; } else if (_buildInfo.Name.Contains("Halo: Reach")) { cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.HaloReach; } else if (_buildInfo.Name.Contains("Halo 4")) { cboxCreatePatchTargetGame.SelectedIndex = (int)TargetGame.Halo4; } else { cboxCreatePatchTargetGame.SelectedIndex = 6; // Other } break; } } cacheStream.Dispose(); }
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 database = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml"); var buildInfo = CacheFileLoader.FindEngineDescription(stream, database); if (buildInfo.Engine != EngineType.ThirdGeneration) { Console.WriteLine("Only third-generation map files are supported."); return; } var cacheFile = new ThirdGenCacheFile(stream, buildInfo, args[0]); 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}", buildInfo.BuildVersion); 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); } }