// end Convert // Datafile private void saveRawDataAsToolStripMenuItem_Click(object sender, EventArgs e) { if (treeView.SelectedNode == null) { return; } EntryTreeNode node = (EntryTreeNode)treeView.SelectedNode; Forge forge = node.Forge; saveFileDialog.FileName = node.Text; if (saveFileDialog.ShowDialog() == DialogResult.OK) { Forge.FileEntry entry = forge.GetFileEntry(node.Text); byte[] data = forge.GetRawData(entry); try { File.WriteAllBytes(saveFileDialog.FileName, data); } catch (IOException ee) { Console.WriteLine(ee); } finally { MessageBox.Show("Done"); } } }
// Datafile private void saveRawDataAsToolStripMenuItem_Click(object sender, EventArgs e) { if (treeView.SelectedNode == null) { return; } EntryTreeNode node = (EntryTreeNode)treeView.SelectedNode; Forge forge = node.GetForge(); saveFileDialog.FileName = $"{node.Text}.dat"; saveFileDialog.Filter = "Raw Data|*.dat|All Files|*.*"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { Forge.FileEntry entry = forge.GetFileEntry(node.Text); byte[] data = forge.GetRawData(entry); try { File.WriteAllBytes(saveFileDialog.FileName, data); } catch (IOException ee) { Console.WriteLine(ee); } finally { MessageBox.Show("Extracted decompressed data.", "Success"); } } }
private void saveDecompressedDataAsToolStripMenuItem_Click(object sender, EventArgs e) { if (treeView.SelectedNode == null) { return; } EntryTreeNode node = (EntryTreeNode)treeView.SelectedNode; Forge forge = node.GetForge(); string text = node.Text; byte[] decompressedData = null; BeginMarquee(); Helpers.DoBackgroundWork(() => { Forge.FileEntry entry = forge.GetFileEntry(text); byte[] rawData = forge.GetRawData(entry); decompressedData = Odyssey.ReadFile(rawData); }, () => { EndMarquee(); // failure if (decompressedData.Length == 0 || decompressedData == null) { MessageBox.Show("Could not decompress data.", "Failure"); return; } saveFileDialog.FileName = string.Concat(node.Text, ".", Helpers.ExtensionForGame(node.Game)); saveFileDialog.Filter = $"{Helpers.NameOfGame(node.Game)} Data|*.{Helpers.ExtensionForGame(node.Game)}|All Files|*.*"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { try { File.WriteAllBytes(saveFileDialog.FileName, decompressedData); } catch (IOException ee) { Console.WriteLine(ee); } finally { MessageBox.Show("Done"); } } }); }
private void saveDecompressedDataAsToolStripMenuItem_Click(object sender, EventArgs e) { if (treeView.SelectedNode == null) { return; } EntryTreeNode node = (EntryTreeNode)treeView.SelectedNode; Forge forge = node.Forge; string text = node.Text; byte[] decompressedData = null; BeginMarquee(); Helpers.DoBackgroundWork(() => { Forge.FileEntry entry = forge.GetFileEntry(text); byte[] rawData = forge.GetRawData(entry); decompressedData = Odyssey.ReadFile(rawData); }, () => { EndMarquee(); saveFileDialog.FileName = $"{node.Text}.dec"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { try { File.WriteAllBytes(saveFileDialog.FileName, decompressedData); } catch (IOException ee) { Console.WriteLine(ee); } finally { MessageBox.Show("Done"); } } }); }
public static bool ExtractTextureMap(string fileName, Forge forge) { using (Stream stream = new FileStream($"{fileName}-combined", FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader reader = new BinaryReader(stream)) { // this is omnipresent DatafileHeader header = new DatafileHeader { ResourceType = reader.ReadInt32(), FileSize = reader.ReadInt32(), FileNameSize = reader.ReadInt32() }; header.FileName = reader.ReadChars(header.FileNameSize); // ignore the 2 bytes, file ID, and resource type identifier reader.BaseStream.Seek(14, SeekOrigin.Current); // toppmip 0 TopMip mip0 = new TopMip { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(8, SeekOrigin.Current); mip0.DXTType = DXTExtensions.GetDXT(reader.ReadInt32()); reader.BaseStream.Seek(4, SeekOrigin.Current); mip0.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(81, SeekOrigin.Current); // topmip 1 TopMip mip1 = new TopMip { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(8, SeekOrigin.Current); mip1.DXTType = DXTExtensions.GetDXT(reader.ReadInt32()); reader.BaseStream.Seek(4, SeekOrigin.Current); mip1.Mipmaps = reader.ReadInt32(); // locate the two topmips, if they exist if (forge.FileEntries.Where(x => x.NameTable.Name.Contains(Path.GetFileName(fileName) + "_TopMip")).Count() == 2) { Forge.FileEntry topMipEntry = forge.FileEntries.Where(x => x.NameTable.Name == Path.GetFileName(fileName) + "_TopMip_0").First(); // extract, read, and create DDS images with the first topmips byte[] rawData = forge.GetRawData(topMipEntry); Helpers.WriteToTempFile(topMipEntry.NameTable.Name, rawData); ReadFile(Helpers.GetTempPath(topMipEntry.NameTable.Name)); ExtractTopMip(Helpers.GetTempPath(topMipEntry.NameTable.Name), mip0); } else // topmips do not exist. fear not! there is still image data found here. let us use that. { reader.BaseStream.Seek(25, SeekOrigin.Current); TextureMap map = new TextureMap { DataSize = reader.ReadInt32() }; byte[] mipmapData = reader.ReadBytes(map.DataSize); Helpers.WriteTempDDS(fileName, mipmapData, mip0.Width, mip0.Height, mip0.Mipmaps, mip0.DXTType); } } } return(true); }
private void treeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) { if (e.Node == null || e.Node.Tag == null) { return; } EntryTreeNode curNode = (EntryTreeNode)e.Node; string text = curNode.Text; string tag = (string)curNode.Tag; // 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 (currentForge.FileEntries.Length > 10000 && MessageBox.Show("This forge file contains more " + "than 10000 entries (" + currentForge.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 = currentForge.FileEntries.Length; // load entries into this forge's tree node for (int i = 0; i < currentForge.FileEntries.Length; i++) { string name = currentForge.FileEntries[i].NameTable.Name; EntryTreeNode node = new EntryTreeNode { Text = name, Tag = string.Format("{0}{1}{2}", curNode.Tag, FORGE_ENTRY_IDENTIFIER, name), // set the tag of this file's tree node Size = currentForge.FileEntries[i].IndexTable.RawDataSize }; node.Nodes.Add(new EntryTreeNode()); // add empty node (for entry's contents) curNode.Nodes.Add(node); 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 or if data as a file does not exist if (curNode.Nodes.Count == 1 && curNode.Nodes[0].Text == "" && !File.Exists(Helpers.GetTempPath(text))) { BeginMarquee(); Helpers.DoBackgroundWork(() => { Forge.FileEntry entry = currentForge.GetFileEntry(text); byte[] rawData = currentForge.GetRawData(entry); Helpers.WriteToTempFile(text, rawData); Odyssey.ReadFile(Helpers.GetTempPath(text)); }, () => { EndMarquee(); // remove nodes curNode.Nodes.Clear(); string combined = $"{Helpers.GetTempPath(text)}-combined"; // look for supported resource types 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)) { curNode.Nodes.Add(new EntryTreeNode { Text = loc.Type.ToString(), Tag = string.Format("{0}{1}{2}", tag, FORGE_SUBENTRY_IDENTIFIER, loc.Type.ToString()), ResourceType = loc.Type }); } } } }); } } }
public static void ExtractTextureMap(string fileName, EntryTreeNode node, Action <string> completionAction) { string name = Path.GetFileNameWithoutExtension(fileName); using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (stream.Length == 0) { return; } using (BinaryReader reader = new BinaryReader(stream)) { DatafileHeader header = new DatafileHeader { ResourceIdentifier = reader.ReadUInt32(), FileSize = reader.ReadInt32(), FileNameSize = reader.ReadInt32() }; header.FileName = reader.ReadChars(header.FileNameSize); reader.BaseStream.Seek(9, SeekOrigin.Current); // fileID + 1 skipped bytes if (header.ResourceIdentifier != (uint)ResourceIdentifier.TEXTURE_MAP) { Message.Fail("This is not proper Texture Map data."); } /*// mip 0 * TextureMap mip0 = new TextureMap * { * Width = reader.ReadInt32(), * Height = reader.ReadInt32() * }; * reader.BaseStream.Seek(4, SeekOrigin.Current); * mip0.DXT = DXTExtensions.GetDXT(reader.ReadInt32()); * reader.BaseStream.Seek(8, SeekOrigin.Current); * mip0.Mipmaps = reader.ReadInt32(); * * reader.BaseStream.Seek(39, SeekOrigin.Current); // go to next mip * * // ignore mip 1 * reader.BaseStream.Seek(28, SeekOrigin.Current); * * // locate the two mips, if they exist * if (node.GetForge().FileEntries.Where(x => x.NameTable.Name.Contains(Path.GetFileNameWithoutExtension(fileName) + "_Mip")).Count() > 0) * { * Forge.FileEntry[] mipEntries = node.GetForge().FileEntries.Where(x => x.NameTable.Name == Path.GetFileNameWithoutExtension(fileName) + "_Mip0").ToArray(); * if (mipEntries != null && mipEntries.Length > 0) * { * Forge.FileEntry mipEntry = mipEntries[0]; * * // extract, read, and create a DDS image with the first mip * byte[] rawTopMipData = node.GetForge().GetRawData(mipEntry); * * // read * byte[] topMipData = ReadFile(rawTopMipData); * File.WriteAllBytes(Helpers.GetTempPath(mipEntry.NameTable.Name + "." + Helpers.GameToExtension(node.Game)), topMipData); * * // extract * //ExtractTopMip(topMipData, mipEntry.NameTable.Name, mip0, completionAction); * } * } * else // mips do not exist. fear not! there is still image data found here. let us use that. * { * reader.BaseStream.Seek(12, SeekOrigin.Current); * * /*TextureMap map = new TextureMap(); * map.DataSize = reader.ReadInt32(); * * // test if this dataSize is too big * bool correctSize = true; * if (map.DataSize > reader.BaseStream.Length || map.DataSize < reader.BaseStream.Length - 300) // if the dataSize lies within a reasonable range * { * correctSize = false; * } * * // test again, 14 bytes later * if (!correctSize) * { * reader.BaseStream.Seek(14, SeekOrigin.Current); * map.DataSize = reader.ReadInt32(); * } * * byte[] mipmapData = reader.ReadBytes(map.DataSize); * * // write DDS file * TopMip mip = mip0; * Helpers.WriteTempDDS(name, mipmapData, mip.Width, mip.Height, mip.Mipmaps, mip.DXTType, () => * { * Helpers.ConvertDDS($"{Helpers.GetTempPath(name)}.dds", fixNormals: name.Contains("NormalMap"), completionAction: (error) => { * if (error) * completionAction("FAILED"); * else * completionAction($"{Helpers.GetTempPath(name)}.png"); * }); * });* * }*/ // TextureMap reader.BaseStream.Seek(5, SeekOrigin.Current); // identifier + 1 skipped byte TextureMap textureMap = new TextureMap { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(4, SeekOrigin.Current); // 4 skipped bytes textureMap.DXT = (DXT)reader.ReadInt32(); reader.BaseStream.Seek(8, SeekOrigin.Current); // 8 skipped bytes textureMap.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(12, SeekOrigin.Current); // 3 skipped ints reader.BaseStream.Seek(2, SeekOrigin.Current); // CompiledTopMip CompiledTopMip[] compiledTopMips = new CompiledTopMip[reader.ReadInt32()]; reader.BaseStream.Seek(1, SeekOrigin.Current); // read CompiledTopMips for (int i = 0; i < compiledTopMips.Length; i++) { compiledTopMips[i].FileID = reader.ReadInt64(); reader.BaseStream.Seek(1, SeekOrigin.Current); // 1 skipped byte } reader.BaseStream.Seek(8, SeekOrigin.Current); // CompiledTextureMap reader.BaseStream.Seek(12, SeekOrigin.Current); // identifier + two skipped ints CompiledTextureMap compiledTextureMap = new CompiledTextureMap { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(4, SeekOrigin.Current); // 1 skipped int compiledTextureMap.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(4, SeekOrigin.Current); // 1 skipped int compiledTextureMap.DXT = (DXT)reader.ReadInt32(); reader.BaseStream.Seek(16, SeekOrigin.Current); // 4 skipped ints // locate the parent forge tree node EntryTreeNode forgeNode = (EntryTreeNode)node.Parent.Parent; if (forgeNode.Type != EntryTreeNodeType.FORGE) { Message.Fail("Failed to locate the forge node."); return; } // check to see if there is a topmip if (compiledTopMips.Select(x => x.FileID).Count() > 0 && compiledTopMips.Select(x => x.FileID).First() != 0) { // search for file IDs from the CompiledTextureMaps if (forgeNode.Nodes.Cast <EntryTreeNode>().Where(x => x.FileID == compiledTopMips[0].FileID).Count() == 0) { if (Message.Show("Failed to locate the Mip0. Would you like to try extracting the TextureMap's internal image data?", "Failed", MessageBoxButtons.YesNo) == DialogResult.Yes) { ExtractInternalTexture(reader, textureMap, name, completionAction); return; } else { return; } } EntryTreeNode mip0Node = forgeNode.Nodes.Cast <EntryTreeNode>().Where(x => x.FileID == compiledTopMips[0].FileID).First(); if (node.GetForge().FileEntries.Where(x => x.IndexTable.FileDataID == compiledTopMips[0].FileID).Count() == 0) { Message.Fail("Failed to locate the Mip0 in the forge."); return; } Forge.FileEntry mip0Entry = node.GetForge().FileEntries.Where(x => x.IndexTable.FileDataID == compiledTopMips[0].FileID).First(); // read byte[] rawMip0Data = node.GetForge().GetRawData(mip0Entry); byte[] mip0Data = ReadFile(rawMip0Data); // save for future use File.WriteAllBytes(Helpers.GetTempPath($"{mip0Entry.NameTable.Name}.{Helpers.GameToExtension(node.Game)}"), mip0Data); // extract Odyssey.ExtractTopMip(mip0Data, mip0Entry.NameTable.Name, compiledTextureMap, completionAction); } else { // use the image data within this file ExtractInternalTexture(reader, textureMap, name, completionAction); } } } }
public static void ExtractTextureMap(string fileName, EntryTreeNode node, Action <string> completionAction) { string name = Path.GetFileNameWithoutExtension(fileName); using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (stream.Length == 0) { return; } using (BinaryReader reader = new BinaryReader(stream)) { DatafileHeader header = new DatafileHeader { ResourceType = reader.ReadInt32(), FileSize = reader.ReadInt32(), FileNameSize = reader.ReadInt32() }; header.FileName = reader.ReadChars(header.FileNameSize); // ignore the 1 byte, file ID, resource type, and 1 extra byte reader.BaseStream.Seek(14, SeekOrigin.Current); // mip 0 Mip mip0 = new Mip { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(8, SeekOrigin.Current); mip0.DXTType = DXTExtensions.GetDXT(reader.ReadInt32()); reader.BaseStream.Seek(4, SeekOrigin.Current); mip0.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(39, SeekOrigin.Current); // go to next mip // mip 1 Mip mip1 = new Mip { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(8, SeekOrigin.Current); mip1.DXTType = DXTExtensions.GetDXT(reader.ReadInt32()); reader.BaseStream.Seek(4, SeekOrigin.Current); mip1.Mipmaps = reader.ReadInt32(); // locate the two mips, if they exist if (node.GetForge().FileEntries.Where(x => x.NameTable.Name.Contains(Path.GetFileNameWithoutExtension(fileName) + "_Mip")).Count() == 2) { Forge.FileEntry[] mipEntries = node.GetForge().FileEntries.Where(x => x.NameTable.Name == Path.GetFileNameWithoutExtension(fileName) + "_Mip0").ToArray(); if (mipEntries.Length > 0) { Forge.FileEntry mipEntry = mipEntries[0]; // extract, read, and create a DDS image with the first mip byte[] rawTopMipData = node.GetForge().GetRawData(mipEntry); //Helpers.WriteToFile(mipEntry.NameTable.Name, rawData, true); // read //ReadFile(Helpers.GetTempPath(mipEntry.NameTable.Name)); byte[] topMipData = ReadFile(rawTopMipData); // extract //ExtractTopMip(Helpers.GetTempPath(mipEntry.NameTable.Name), mip0, completionAction); ExtractTopMip(topMipData, mipEntry.NameTable.Name, mip0, completionAction); } } else // mips do not exist. fear not! there is still image data found here. let us use that. { reader.BaseStream.Seek(12, SeekOrigin.Current); TextureMap map = new TextureMap { DataSize = reader.ReadInt32() }; byte[] mipmapData = reader.ReadBytes(map.DataSize); // write DDS file Helpers.WriteTempDDS(name, mipmapData, mip1.Width, mip1.Height, mip1.Mipmaps, mip1.DXTType, () => { Helpers.ConvertDDS($"{Helpers.GetTempPath(name)}.dds", (bool error) => { if (error) { completionAction("FAILED"); } else { completionAction($"{Helpers.GetTempPath(name)}.png"); } }); }); } } } }