예제 #1
0
        private void extractTags(bool withRaw, TagEntry tag)
        {
            // Ask where to save the extracted tag collection
            var sfd = new SaveFileDialog
            {
                Title = "Save Tag Set",
                Filter = "Tag Container Files|*.tagc"
            };
            bool? result = sfd.ShowDialog();
            if (!result.Value)
                return;

            // Make a tag container
            var container = new TagContainer();

            // Recursively extract tags
            var tagsToProcess = new Queue<ITag>();
            var tagsProcessed = new HashSet<ITag>();
            var resourcesToProcess = new Queue<DatumIndex>();
            var resourcesProcessed = new HashSet<DatumIndex>();
            var resourcePagesProcessed = new HashSet<ResourcePage>();
            tagsToProcess.Enqueue(tag.RawTag);

            ResourceTable resources = null;
            using (var reader = _mapManager.OpenRead())
            {
                while (tagsToProcess.Count > 0)
                {
                    var currentTag = tagsToProcess.Dequeue();
                    if (tagsProcessed.Contains(currentTag))
                        continue;

                    // Get the plugin path
                    var className = VariousFunctions.SterilizeTagClassName(CharConstant.ToString(currentTag.Class.Magic)).Trim();
                    var pluginPath = string.Format("{0}\\{1}\\{2}.xml", VariousFunctions.GetApplicationLocation() + @"Plugins",
                        _buildInfo.Settings.GetSetting<string>("plugins"), className);

                    // Extract dem data blocks
                    var blockBuilder = new DataBlockBuilder(reader, currentTag, _cacheFile, _buildInfo);
                    using (var pluginReader = XmlReader.Create(pluginPath))
                        AssemblyPluginLoader.LoadPlugin(pluginReader, blockBuilder);

                    foreach (var block in blockBuilder.DataBlocks)
                        container.AddDataBlock(block);

                    // Add data for the tag that was extracted
                    var tagName = _cacheFile.FileNames.GetTagName(currentTag) ?? currentTag.Index.ToString();
                    var extractedTag = new ExtractedTag(currentTag.Index, currentTag.MetaLocation.AsPointer(), currentTag.Class.Magic,
                        tagName);
                    container.AddTag(extractedTag);

                    // Mark the tag as processed and then enqueue all of its child tags and resources
                    tagsProcessed.Add(currentTag);
                    foreach (var tagRef in blockBuilder.ReferencedTags)
                        tagsToProcess.Enqueue(_cacheFile.Tags[tagRef]);
                    foreach (var resource in blockBuilder.ReferencedResources)
                        resourcesToProcess.Enqueue(resource);
                }

                // Load the resource table in if necessary
                if (resourcesToProcess.Count > 0)
                    resources = _cacheFile.Resources.LoadResourceTable(reader);
            }

            // Extract resource info
            if (resources != null)
            {
                while (resourcesToProcess.Count > 0)
                {
                    var index = resourcesToProcess.Dequeue();
                    if (resourcesProcessed.Contains(index))
                        continue;

                    // Add the resource
                    var resource = resources.Resources[index.Index];
                    container.AddResource(new ExtractedResourceInfo(index, resource));

                    // Add data for its pages
                    if (resource.Location == null) continue;

                    if (resource.Location.PrimaryPage != null &&
                        !resourcePagesProcessed.Contains(resource.Location.PrimaryPage))
                    {
                        container.AddResourcePage(resource.Location.PrimaryPage);
                        resourcePagesProcessed.Add(resource.Location.PrimaryPage);

                        if (withRaw)
                        {
                            using (var fileStream = File.OpenRead(_cacheLocation))
                            {
                                var resourceFile = _cacheFile;
                                Stream resourceStream = fileStream;
                                if (resource.Location.PrimaryPage.FilePath != null)
                                {
                                    var resourceCacheInfo =
                                    App.AssemblyStorage.AssemblySettings.HalomapResourceCachePaths.FirstOrDefault(
                                        r => r.EngineName == _buildInfo.Name);

                                    var resourceCachePath = (resourceCacheInfo != null)
                                        ? resourceCacheInfo.ResourceCachePath
                                        : Path.GetDirectoryName(_cacheLocation);

                                    resourceCachePath = Path.Combine(resourceCachePath ?? "", Path.GetFileName(resource.Location.PrimaryPage.FilePath));

                                    if (!File.Exists(resourceCachePath))
                                    {
                                        MetroMessageBox.Show("Unable to extract tag",
                                            "Unable to extract tag, because a resource it relies on is in a external cache '{0}' that could not be found. Check Assembly's settings and set the file path to resource caches.");
                                        return;
                                    }

                                    resourceStream =
                                        File.OpenRead(resourceCachePath);
                                    resourceFile = new ThirdGenCacheFile(new EndianReader(resourceStream, Endian.BigEndian), _buildInfo,
                                        _cacheFile.BuildString);
                                }

                                var extractor = new ResourcePageExtractor(resourceFile);
                                byte[] pageData;
                                using (var pageStream = new MemoryStream())
                                {
                                    extractor.ExtractPage(resource.Location.PrimaryPage, resourceStream, pageStream);
                                    pageData = new byte[pageStream.Length];
                                    Buffer.BlockCopy(pageStream.GetBuffer(), 0, pageData, 0, (int) pageStream.Length);
                                }
                                container.AddExtractedResourcePage(new ExtractedPage(pageData, resource.Location.PrimaryPage.Index));
                            }
                        }
                    }
                    if (resource.Location.SecondaryPage == null || resourcePagesProcessed.Contains(resource.Location.SecondaryPage))
                        continue;

                    container.AddResourcePage(resource.Location.SecondaryPage);
                    resourcePagesProcessed.Add(resource.Location.SecondaryPage);

                    if (withRaw)
                    {
                        using (var fileStream = File.OpenRead(_cacheLocation))
                        {
                            var resourceFile = _cacheFile;
                            Stream resourceStream = fileStream;
                            if (resource.Location.SecondaryPage.FilePath != null)
                            {
                                var resourceCacheInfo =
                                    App.AssemblyStorage.AssemblySettings.HalomapResourceCachePaths.FirstOrDefault(
                                        r => r.EngineName == _buildInfo.Name);

                                var resourceCachePath = (resourceCacheInfo != null)
                                    ? resourceCacheInfo.ResourceCachePath
                                    : Path.GetDirectoryName(_cacheLocation);

                                resourceCachePath = Path.Combine(resourceCachePath ?? "", Path.GetFileName(resource.Location.SecondaryPage.FilePath));

                                if (!File.Exists(resourceCachePath))
                                {
                                    MetroMessageBox.Show("Unable to extract tag",
                                        "Unable to extract tag, because a resource it relies on is in a external cache '{0}' that could not be found. Check Assembly's settings and set the file path to resource caches.");
                                    return;
                                }

                                resourceStream =
                                    File.OpenRead(resourceCachePath);
                                resourceFile = new ThirdGenCacheFile(new EndianReader(resourceStream, Endian.BigEndian), _buildInfo,
                                    _cacheFile.BuildString);
                            }

                            var extractor = new ResourcePageExtractor(resourceFile);
                            byte[] pageData;
                            using (var pageStream = new MemoryStream())
                            {
                                extractor.ExtractPage(resource.Location.SecondaryPage, resourceStream, pageStream);
                                pageData = new byte[pageStream.Length];
                                Buffer.BlockCopy(pageStream.GetBuffer(), 0, pageData, 0, (int)pageStream.Length);
                            }
                            container.AddExtractedResourcePage(new ExtractedPage(pageData, resource.Location.SecondaryPage.Index));
                        }
                    }
                }
            }

            // Write it to a file
            using (var writer = new EndianWriter(File.Open(sfd.FileName, FileMode.Create, FileAccess.Write), Endian.BigEndian))
                TagContainerWriter.WriteTagContainer(container, writer);

            // YAY!
            MetroMessageBox.Show("Extraction Successful",
                "Extracted " +
                container.Tags.Count + " tag(s), " +
                container.DataBlocks.Count + " data block(s), " +
                container.ResourcePages.Count + " resource page pointer(s), " +
                container.ExtractedResourcePages.Count + " extracted resource page(s), and " +
                container.Resources.Count + " resource pointer(s).");
        }
예제 #2
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 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);
        }
예제 #3
0
        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();
        }