Example #1
0
        // 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);
            }
        }
Example #2
0
        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();
        }
Example #3
0
        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);
            }
        }