private void decompressFileToolStripMenuItem_Click(object sender, EventArgs e) { if (openFileDialog.ShowDialog() == DialogResult.OK) { saveFileDialog.Filter = "Decompressed Data|*.dec|All files|*.*"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { using (Stream stream = new FileStream(openFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader reader = new BinaryReader(stream)) { if (Helpers.LocateRawDataIdentifier(reader).Length < 2) { MessageBox.Show("Operation failed.", "Failure"); return; } BeginMarquee(); long secondRawData = Helpers.LocateRawDataIdentifier(reader)[1]; reader.BaseStream.Seek(10, SeekOrigin.Current); // ignore everything until the compression byte byte compression = reader.ReadByte(); bool success = false; Helpers.DoBackgroundWork(() => { if (secondRawData > 0) { if (compression == 0x08) { success = Odyssey.ReadFile(openFileDialog.FileName, false, saveFileDialog.FileName); } else if (compression == 0x05) { success = Steep.ReadFile(openFileDialog.FileName, false, saveFileDialog.FileName); } } }, () => { EndMarquee(); if (success) { MessageBox.Show("Decompressed file successfully. Check the folder where the compressed file is located.", "Success"); } else { MessageBox.Show("Unknown compression type.", "Failure"); } }); } } } } }
private List <EntryTreeNode> PopulateEntry(EntryTreeNode node) { // extract the contents from the forge Forge forge = node.GetForge(); byte[] data = forge.GetRawData(node.Offset, node.Size); // decompress string file = $"{node.Text}.{Helpers.ExtensionForGame(node.Game)}"; if (node.Game == Game.ODYSSEY) { Helpers.WriteToFile(file, Odyssey.ReadFile(data), true); } else if (node.Game == Game.ORIGINS) { Helpers.WriteToFile(file, Odyssey.ReadFile(data), true); } else if (node.Game == Game.STEEP) { Helpers.WriteToFile(file, Steep.ReadFile(data), true); } // path will hold the file name node.Path = file; // get resource locations and create nodes List <EntryTreeNode> nodes = new List <EntryTreeNode>(); using (Stream stream = new FileStream(Helpers.GetTempPath(file), FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader reader = new BinaryReader(stream)) { Helpers.ResourceLocation[] locations = Helpers.LocateResourceIdentifiers(reader); foreach (Helpers.ResourceLocation location in locations) { nodes.Add(new EntryTreeNode { Game = node.Game, Path = file, ResourceType = location.Type, Text = location.Type.ToString(), Type = EntryTreeNodeType.SUBENTRY }); } } } return(nodes); }
private void HandleSubentryNode(EntryTreeNode node) { if (node.ResourceType == ResourceType.MESH) // meshes/models { if (node.Game == Game.ODYSSEY) { // to be implemented } else if (node.Game == Game.ORIGINS) { /*Origins.Submesh[] submeshes = Origins.ExtractModel(Helpers.GetTempPath(node.Path), node, () => * { * Console.WriteLine("EXTRACTED MODEL"); * }); * foreach (Origins.Submesh submesh in submeshes) * { * gl.Meshes.Add(new DynamicMesh(submesh)); * }*/ } else if (node.Game == Game.STEEP) { // to be implemented } } else if (node.ResourceType == ResourceType.TEXTURE_MAP) // texture maps { if (node.Game == Game.ODYSSEY || node.Game == Game.ORIGINS) { Odyssey.ExtractTextureMap(Helpers.GetTempPath(node.Path), node, (string path) => { HandleTextureMap(path); }); } else if (node.Game == Game.STEEP) // Needs string path too { Steep.ExtractTextureMap(Helpers.GetTempPath(node.Path), node, (string path) => { HandleTextureMap(path); }); } } }
private void treeView_AfterSelect(object sender, TreeViewEventArgs e) { if (e.Node == null || e.Node.Tag == null) { return; } EntryTreeNode node = (EntryTreeNode)e.Node; Forge forge = node.Forge; TreeNode parent = (EntryTreeNode)node.Parent; string text = node.Text; string tag = (string)node.Tag; long size = node.Size; ResourceType type = node.ResourceType; // reset the picture box and rich text box // ToDo: empty 3D viewer pictureBox.ImageLocation = ""; richTextBox.Text = ""; if (tag.Contains(".forge")) { if (text.EndsWith(".forge")) // forge file { // dump resources used by currentForge if (currentForge != null) { currentForge.Dump(); } currentForge = new Forge(tag); node.Forge = currentForge; } else // forge entry/subentry { // forge subentry if (tag.Contains(FORGE_ENTRY_IDENTIFIER) && tag.Contains(FORGE_SUBENTRY_IDENTIFIER)) { if (type == ResourceType.TEXTURE_MAP) { string parentText = Helpers.GetTempPath(parent.Text); if (node.Game == Game.ODYSSEY || node.Game == Game.ORIGINS) { Odyssey.ExtractTextureMap(parentText, forge, () => { if (File.Exists($"{Helpers.GetTempPath(parent.Text)}.png")) { currentImgPath = $"{Helpers.GetTempPath(parent.Text)}.png"; } else if (File.Exists($"{Helpers.GetTempPath(parent.Text)}_TopMip_0.png")) { currentImgPath = $"{Helpers.GetTempPath(parent.Text)}_TopMip_0.png"; } Invoke(new Action(() => { if (!string.IsNullOrEmpty(currentImgPath)) { UpdatePictureBox(Image.FromFile(currentImgPath)); } zoomDropDownButton.Text = "Zoom Level: 100%"; tabControl.SelectedIndex = 1; })); }); } else { Steep.ExtractTextureMap(parentText, forge, () => { if (File.Exists($"{Helpers.GetTempPath(parent.Text)}.png")) { currentImgPath = $"{Helpers.GetTempPath(parent.Text)}.png"; } else if (File.Exists($"{Helpers.GetTempPath(parent.Text)}_Mip0.png")) { currentImgPath = $"{Helpers.GetTempPath(parent.Text)}_Mip0.png"; } Invoke(new Action(() => { if (!string.IsNullOrEmpty(currentImgPath)) { UpdatePictureBox(Image.FromFile(currentImgPath)); } zoomDropDownButton.Text = "Zoom Level: 100%"; tabControl.SelectedIndex = 1; })); }); } } } } } else if (text.EndsWith(".png")) { pictureBox.Image = Image.FromFile(tag); pictureBox.Refresh(); if (pictureBox.Image != null) { imageDimensStatusLabel.Text = $"Dimensions: {pictureBox.Image.Width}x{pictureBox.Image.Height}"; } tabControl.SelectedIndex = 1; } else if (text.EndsWith(".ini") || text.EndsWith(".txt") || text.EndsWith(".log")) { richTextBox.Text = string.Join("\n", File.ReadAllLines(tag)); tabControl.SelectedIndex = 2; } else if (text.EndsWith(".pck")) { SoundpackBrowser browser = new SoundpackBrowser(); browser.LoadPack(tag); browser.Show(); } // update path status label if (!tag.Contains(FORGE_ENTRY_IDENTIFIER)) { pathStatusLabel.Text = tag; } // update size status label if (size > -1) { sizeStatusLabel.Text = $"Size: {Helpers.BytesToString(size)}"; } }
private void treeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) { if (e.Node == null || e.Node.Tag == null) { return; } EntryTreeNode node = (EntryTreeNode)e.Node; int levels = LevelsDeep(node.FullPath); Forge forge = levels == 1 ? node.Forge : levels == 2 ? ((EntryTreeNode)node.Parent).Forge: ((EntryTreeNode)node.Parent.Parent).Forge; Console.WriteLine(levels + " deep"); string text = node.Text; string tag = (string)node.Tag; if (string.IsNullOrEmpty(text)) { return; } // a forge file if (tag.EndsWith(".forge")) { // dump resources used by currentForge if (currentForge != null) { currentForge.Dump(); } currentForge = new Forge(tag); Helpers.DoBackgroundWork(() => { currentForge.Read(); }, () => { // show message if there are over 10000 files in the forge if (forge.FileEntries.Length > 10000 && MessageBox.Show("This forge file contains more " + "than 10000 entries (" + forge.FileEntries.Length + " exactly). Loading all these " + "entries will take a while and Blacksmith will freeze.\n\nContinue?", "Large forge file!", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } // delete the empty tree node e.Node.Nodes.RemoveAt(0); // show and update the progress bar toolStripProgressBar.Visible = true; toolStripProgressBar.Value = 0; toolStripProgressBar.Maximum = forge.FileEntries.Length; Helpers.DoBackgroundWork(() => { // load entries into this forge's tree node if (!forge.IsFullyRead()) { return; } for (int i = 0; i < forge.FileEntries.Length; i++) { if (forge.FileEntries[i].NameTable == null) { continue; } string name = forge.FileEntries[i].NameTable.Name; EntryTreeNode n = new EntryTreeNode { Text = name, Forge = forge, Tag = $"{node.Tag}{FORGE_ENTRY_IDENTIFIER}{name}", // set the tag of this file's tree node Offset = forge.FileEntries[i].IndexTable.OffsetToRawDataTable, Size = forge.FileEntries[i].IndexTable.RawDataSize, Game = node.Game }; n.Nodes.Add(new EntryTreeNode()); // add empty node (for entry's contents) Invoke(new Action(() => { if (this != null && toolStripProgressBar.Value < 3001) // I recieved an error stating that the progress bar cannot go above 3001 { node.Nodes.Add(n); toolStripProgressBar.Value++; } })); } }, () => { // reset and hide the progress bar toolStripProgressBar.Value = toolStripProgressBar.Maximum = 0; toolStripProgressBar.Visible = false; }); }); } // forge entry else if (tag.Contains(FORGE_ENTRY_IDENTIFIER) && !tag.Contains(FORGE_SUBENTRY_IDENTIFIER)) { // extract, if the entry has an empty node if (node.Nodes.Count == 1 && node.Nodes[0].Text == "") { BeginMarquee(); Helpers.DoBackgroundWork(() => { byte[] rawData = forge.GetRawData(node.Offset, (int)node.Size); Helpers.WriteToFile($"{text}.ext", rawData, true); if (node.Game == Game.ODYSSEY || node.Game == Game.ORIGINS) // temporary, until this Origins no longer works like Odyssey { Odyssey.ReadFile(Helpers.GetTempPath($"{text}.ext")); } else { Steep.ReadFile(Helpers.GetTempPath($"{text}.ext")); } }, () => { EndMarquee(); // remove nodes node.Nodes.Clear(); // look for supported resource types. steep stays out, for now (because it causes crashes). string combined = $"{Helpers.GetTempPath(text)}.dec"; if (File.Exists(combined)) { using (Stream stream = new FileStream(combined, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader reader = new BinaryReader(stream)) { // create nodes based on located resource types foreach (Helpers.ResourceLocation loc in Helpers.LocateResourceIdentifiers(reader)) { node.Nodes.Add(new EntryTreeNode { Text = loc.Type.ToString(), Tag = $"{tag}{FORGE_SUBENTRY_IDENTIFIER}{loc.Type.ToString()}", ResourceType = loc.Type, Game = node.Game }); } } } } }); } } }