public void ParseRDTNode(int offsetOfThisNode, string baseString) { int subnodeCount = filebytes[offsetOfThisNode]; string currentStateOfString = baseString; for (int i = 0; i < subnodeCount; i++) { char letter = (char)filebytes[offsetOfThisNode + (i * 5) + 1]; if ((byte)letter == 0x00) //it's the end of the string { if (!filenamesAndOffsets.ContainsKey(currentStateOfString)) { filenamesAndOffsets.Add(currentStateOfString, BitConverter.ToInt32(filebytes, offsetOfThisNode + (i * 5) + 2)); archivedfile newFile = new archivedfile(); newFile.filename = currentStateOfString; newFile.offset = filenamesAndOffsets[currentStateOfString]; newFile.form1 = form1; newFile.parentrdtfile = this; archivedfiles.Add(newFile); } Console.WriteLine(currentStateOfString + " file offset is " + filenamesAndOffsets[currentStateOfString]); } else //keep following the string { currentStateOfString += letter; ParseRDTNode(BitConverter.ToInt32(filebytes, offsetOfThisNode + (i * 5) + 2), currentStateOfString); } currentStateOfString = baseString; } }
public void SetAuthorDetails() { archivedfile authorFile = embeddedArc.GetFileByName("/info.txt"); saveFileEditor.author.Text = "Author: None"; saveFileEditor.authorNote.Text = "Author's note: None"; if (authorFile != null) { authorFile.ReadFile(); string authorFileText = ""; for (int i = 0; i < authorFile.filebytes.Length; i++) { authorFileText += (char)authorFile.filebytes[i]; } string[] splitAuthorFile = authorFileText.Replace("\r", "").Split('\n'); saveFileEditor.author.Text = "Author: " + splitAuthorFile[0]; if (splitAuthorFile.Length > 1) { saveFileEditor.authorNote.Text = "Author's note: " + splitAuthorFile[1].Replace("[newline]", "\n"); } } }
public void ExportFolder(TreeNode topnode) { NodesForBatchExport = new List <TreeNode>(); NodesForBatchExport.Add(topnode); RecursivelyAddChildrenToExportList(topnode); //now we should have all child, grandchild, etc folders SaveFileDialog saveFileDialog1 = new SaveFileDialog(); saveFileDialog1.FileName = "Save here"; saveFileDialog1.Title = "Choose folder"; saveFileDialog1.CheckPathExists = true; saveFileDialog1.Filter = "Directory |directory"; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { Console.WriteLine(saveFileDialog1.FileName); foreach (TreeNode folder in NodesForBatchExport) { foreach (TreeNode child in folder.Nodes) { if (form1.treeNodesAndArchivedFiles.ContainsKey(child)) //if it's a file { archivedfile file = form1.treeNodesAndArchivedFiles[child]; string path; if (file.filename[0] == '/') { path = Path.GetDirectoryName(saveFileDialog1.FileName) + file.filename.Replace('/', '\\'); } else { path = Path.GetDirectoryName(saveFileDialog1.FileName) + "\\" + file.filename.Replace('/', '\\'); } if (file.filename == "FILENAME_NOT_SET") { path = Path.GetDirectoryName(saveFileDialog1.FileName) + "\\Names_not_found\\" + file.hash + "." + file.filemagic; } Console.WriteLine(path); file.ReadFile(); file.Export(form1.GetOrMakeDirectoryForFileName(path.Replace('/', '\\').Replace(".luc", ".lua"))); } } } } }
public void GetDownloadableMissionName() { archivedfile downloadstrings = embeddedArc.GetFileByName("/strings/downloadstrings.st"); if (downloadstrings == null) { Console.WriteLine("downloadstrings was not found in that arc!"); } else { downloadstrings.ReadFile(); saveFileEditor.downloadableMissionNameDisplay.Text = "Downloadable Mission: " + downloadstrings.STstrings[0]; } }
public void EndHerbertsRevengeChain(int offsetOfThisNode, string currentStateOfString) { if (!filenamesAndOffsets.ContainsKey(currentStateOfString)) { filenamesAndOffsets.Add(currentStateOfString, BitConverter.ToInt32(filebytes, offsetOfThisNode)); offsetOfThisNode += 4; archivedfile newFile = new archivedfile(); newFile.filename = currentStateOfString; newFile.offset = filenamesAndOffsets[currentStateOfString]; newFile.form1 = form1; newFile.parentrdtfile = this; archivedfiles.Add(newFile); } Console.WriteLine(currentStateOfString + " file offset is " + filenamesAndOffsets[currentStateOfString]); }
public void RDTBlagger3000() //attempts to scrape likely file offsets from the index table. Intended for HR RDTs, where the file tree is in an annoying format { int endOfIndexTable = BitConverter.ToInt32(filebytes, 0x0B); for (int i = 0x12; i < endOfIndexTable; i++) { int possibleOffset = BitConverter.ToInt32(filebytes, i); if (possibleOffset >= endOfIndexTable && possibleOffset < filebytes.Length && filebytes[possibleOffset] == 0x03 && BitConverter.ToInt32(filebytes, possibleOffset + 1) > 0 && BitConverter.ToUInt16(filebytes, possibleOffset + 1) < 65535) { archivedfile newFile = new archivedfile(); newFile.offset = possibleOffset; newFile.filename = "PotentialFile" + newFile.offset.ToString(); newFile.form1 = form1; newFile.parentrdtfile = this; archivedfiles.Add(newFile); } } }
public archivedfile(archivedfile basis) { form1 = basis.form1; spriteEditor = basis.spriteEditor; hash = basis.hash; offset = basis.offset; size = basis.size; filebytes = basis.filebytes; filemagic = basis.filemagic; filename = basis.filename; parentarcfile = basis.parentarcfile; parentrdtfile = basis.parentrdtfile; treeNode = basis.treeNode; should_this_file_be_decompressed__and_compressed_when_read = basis.should_this_file_be_decompressed__and_compressed_when_read; has_LZ11_filesize = basis.has_LZ11_filesize; was_LZ10_compressed = basis.was_LZ10_compressed; was_LZ11_compressed = basis.was_LZ11_compressed; STstrings = basis.STstrings; textFileStringType = basis.textFileStringType; rdtSubfileDataList = basis.rdtSubfileDataList; RDTSpriteNumFrames = basis.RDTSpriteNumFrames; RDTSpriteWidth = basis.RDTSpriteWidth; RDTSpriteHeight = basis.RDTSpriteHeight; RDTSpriteBPP = basis.RDTSpriteBPP; RDTSpriteFrameDurations = basis.RDTSpriteFrameDurations; RDTSpriteAlphaColour = basis.RDTSpriteAlphaColour; }
public void AddSubNodesToByteArray(TreeNode node, Byte[] nodeTree) { nodeTree[posInNodeTree] = (byte)node.Nodes.Count; posInNodeTree++; int basePos = posInNodeTree; posInNodeTree = basePos + (node.Nodes.Count * 5); for (int i = 0; i < node.Nodes.Count; i++) { if (node.Nodes[i].Text == "nullNode") { nodeTree[basePos + (i * 5)] = 0x00; archivedfile file = archivedfiles[NullNodesInArchivedFileOrder.IndexOf(node.Nodes[i])]; List <rdtSubfileData> backuplist = new List <rdtSubfileData>(file.rdtSubfileDataList); //prepare data for import List <Image> images = new List <Image>(); List <Byte[]> palettes = new List <Byte[]>(); List <rdtSubfileData> savedImages = new List <rdtSubfileData>(); List <rdtSubfileData> savedPalettes = new List <rdtSubfileData>(); foreach (rdtSubfileData subfiledata in file.rdtSubfileDataList) //get palettes { if (subfiledata.graphicsType == "palette") { subfiledata.DecompressLZ10IfCompressed(); palettes.Add(subfiledata.filebytes); savedPalettes.Add(subfiledata); } } int imageIndex = 0; List <int> skipIndices = new List <int>(); bool is_modified = false; List <ushort> offsetsX = new List <ushort>(); List <ushort> offsetsY = new List <ushort>(); foreach (rdtSubfileData subfiledata in file.rdtSubfileDataList) //get images { if (subfiledata.graphicsType == "image") { if (subfiledata.image != null) //if it was modified or viewed by the user, use the modified one { images.Add(subfiledata.image); savedImages.Add(subfiledata); is_modified = true; } else //otherwise, just read the existing image for the first time and apply the existing palette { subfiledata.LoadImage(file.GetPalette(palettes[imageIndex], 1, file.RDTSpriteBPP)); images.Add(subfiledata.image); skipIndices.Add(images.Count - 1); //so that we know not to bother rereading it and its palette savedImages.Add(subfiledata); } offsetsX.Add(subfiledata.offsetX); offsetsY.Add(subfiledata.offsetY); imageIndex++; } } //remove the existing images and palette subfiledata in the archivedfile int indexOfFirstImageOrPalette = 0; foreach (rdtSubfileData f in file.rdtSubfileDataList) { if (f.graphicsType != "image" && f.graphicsType != "palette") { indexOfFirstImageOrPalette++; continue; } break; } file.rdtSubfileDataList.RemoveRange(indexOfFirstImageOrPalette, file.rdtSubfileDataList.Count - indexOfFirstImageOrPalette); //now we add the updated images back to the list //make global palette for sprite rdtSubfileData newPalette = new rdtSubfileData(); // read individual frames for (int j = 0; j < images.Count; j++) { //make palette newPalette = new rdtSubfileData(); if (skipIndices.Contains(j)) //no need to reread image data, as the user didn't edit or view it { newPalette = savedPalettes[0]; newPalette.graphicsType = "palette"; newPalette.DecompressLZ10IfCompressed(); file.rdtSubfileDataList.Add(newPalette); file.rdtSubfileDataList.Add(savedImages[j]); } else //the user edited or viewed this file, so rebuild the image and palette { //make palette newPalette = new rdtSubfileData(); Color[] palette = new Color[0]; if (file.RDTSpriteBPP == 4) { palette = new Color[16]; } else if (file.RDTSpriteBPP == 8) { palette = new Color[256]; } //put image colours in palette if (file.RDTSpriteAlphaColour.A == 0 && file.RDTSpriteAlphaColour.R == 0 && file.RDTSpriteAlphaColour.G == 0 && file.RDTSpriteAlphaColour.B == 0) { file.RDTSpriteAlphaColour = file.GetPalette(palettes[j], 1, file.RDTSpriteBPP)[0]; } Color[] coloursToAdd = Get_Unique_Colours(images, palette.Length); Array.Copy(coloursToAdd, 0, palette, 0, coloursToAdd.Length); //Console.WriteLine("number of unique colours: " + coloursToAdd.Length); file.RDTSpriteAlphaColour = Color.FromArgb(0x00, file.RDTSpriteAlphaColour.R, file.RDTSpriteAlphaColour.G, file.RDTSpriteAlphaColour.B); //make sure the dummy A value is 0x00 //now make sure the alpha colour is at index 0 if (palette[0] != file.RDTSpriteAlphaColour) { int checkIndex = 0; while (checkIndex < palette.Length) //go through the palette looking for the alpha colour's current position { if (palette[checkIndex] == file.RDTSpriteAlphaColour) { break; } checkIndex++; } //swap the alpha colour into index 0, and the index 0 colour to where the alpha colour used to be palette[checkIndex] = palette[0]; palette[0] = file.RDTSpriteAlphaColour; } //CREATE BINARY NBFC IMAGE AND PALETTE, THEN MAKE SUBFILEDATAS FOR THEM AND ADD THEM TO LIST //create binary palette newPalette.subfileType = 0x04; newPalette.graphicsType = "palette"; newPalette.filebytes = new byte[1 + (palette.Length * 2)]; int colorindex = 0; foreach (Color c in palette) { ushort ABGR1555Color = form1.ColorToABGR1555(c); newPalette.filebytes[1 + (colorindex * 2)] = (byte)(ABGR1555Color & 0x00FF); newPalette.filebytes[2 + (colorindex * 2)] = (byte)((ABGR1555Color & 0xFF00) >> 8); colorindex++; } file.rdtSubfileDataList.Add(newPalette); //create binary image here rdtSubfileData newImage = new rdtSubfileData(); newImage.subfileType = 0x04; int fakeWidth = images[j].Width; //fakewidth should only be used when setting the size of the byte array, and nowhere else! if (file.RDTSpriteBPP == 4) { while (fakeWidth % 2 != 0) { fakeWidth++; } newImage.filebytes = new byte[8 + ((fakeWidth / 2) * images[j].Height)]; } else { newImage.filebytes = new byte[8 + (fakeWidth * images[j].Height)]; } form1.WriteU16ToArray(newImage.filebytes, 0, (ushort)images[j].Width); form1.WriteU16ToArray(newImage.filebytes, 2, (ushort)images[j].Height); form1.WriteU16ToArray(newImage.filebytes, 4, offsetsX[j]); form1.WriteU16ToArray(newImage.filebytes, 6, offsetsY[j]); int curOffset = 8; Bitmap imageTemp = (Bitmap)images[j]; Color newPixel; if (file.RDTSpriteBPP == 4) { for (int y = 0; y < imageTemp.Height; y++) { for (int x = 0; x < imageTemp.Width; x++) { newPixel = imageTemp.GetPixel(x, y); newImage.filebytes[curOffset] = (byte)(newImage.filebytes[curOffset] | (byte)form1.FindIndexOfColorInPalette(palette, Color.FromArgb(newPixel.A, newPixel.R & 0xF8, newPixel.G & 0xF8, newPixel.B & 0xF8))); if (x < imageTemp.Width - 1) { x++; newPixel = imageTemp.GetPixel(x, y); newImage.filebytes[curOffset] = (byte)(newImage.filebytes[curOffset] | (byte)(form1.FindIndexOfColorInPalette(palette, Color.FromArgb(newPixel.A, newPixel.R & 0xF8, newPixel.G & 0xF8, newPixel.B & 0xF8)) << 4)); } curOffset++; } } } else { for (int y = 0; y < imageTemp.Height; y++) { for (int x = 0; x < imageTemp.Width; x++) { newPixel = imageTemp.GetPixel(x, y); newImage.filebytes[curOffset] = (byte)form1.FindIndexOfColorInPalette(palette, Color.FromArgb(newPixel.A, newPixel.R & 0xF8, newPixel.G & 0xF8, newPixel.B & 0xF8)); curOffset++; } } } file.rdtSubfileDataList.Add(newImage); } } form1.WriteU16ToArray(file.rdtSubfileDataList[2].filebytes, 0, file.RDTSpriteNumFrames); form1.WriteU16ToArray(file.rdtSubfileDataList[2].filebytes, 2, file.RDTSpriteWidth); form1.WriteU16ToArray(file.rdtSubfileDataList[2].filebytes, 4, file.RDTSpriteHeight); file.rdtSubfileDataList[2].filebytes[6] = (byte)file.RDTSpriteBPP; file.rdtSubfileDataList[3].filebytes = new byte[file.RDTSpriteNumFrames * 2]; for (int j = 0; j < file.RDTSpriteFrameDurations.Count; j++) { form1.WriteU16ToArray(file.rdtSubfileDataList[3].filebytes, j * 2, file.RDTSpriteFrameDurations[j]); } file.rdtSubfileDataList[1].RebuildFilebytesFromSettings(); //rebuild centre bounds etc config int offsetOfSubfileTable = 0x11 + nodeTree.Length + data.Count; file.rdtSubfileDataList[0].filebytes = new Byte[8 + ((file.rdtSubfileDataList.Count - 1) * 4)]; //make space in the subfile table file.rdtSubfileDataList[0].filebytes[0] = 2; file.rdtSubfileDataList[0].filebytes[4] = 1; form1.WriteU16ToArray(file.rdtSubfileDataList[0].filebytes, 0x0A, (ushort)(file.rdtSubfileDataList.Count - 2)); int pos_in_subfiletable = 0x0C; //a lot of things need to be updated before the following happens! I don't know if they all read into their filebytes in the first place, so you need to rebuild them first! int spritePaletteOffset = 0; //global palette for the sprite so that it can just be pasted around foreach (rdtSubfileData subfiledata in file.rdtSubfileDataList) { subfiledata.writeAddress = 0; int offsetOfThisSubfile = 0; bool dontWrite = false; int offset_in_subfiletable_where_address_should_be_written = (offsetOfSubfileTable - (0x11 + nodeTree.Length)) + pos_in_subfiletable; if (file.rdtSubfileDataList.IndexOf(subfiledata) > 0) //if it's not the subfile table, add an entry to the subfile table { if (offsetOfThisSubfile == 0) //if it wasn't written to by the previous check { offsetOfThisSubfile = 0x11 + nodeTree.Length + data.Count; subfiledata.writeAddress = offsetOfThisSubfile; } if (subfiledata.graphicsType == "palette" && spritePaletteOffset != 0) //if it's not the first palette to be processed, just store a reference to the earlier palette { dontWrite = true; offsetOfThisSubfile = spritePaletteOffset; } else if (subfiledata.graphicsType == "palette") //but if it is the first one, store its offset so we can reference it later { spritePaletteOffset = offsetOfThisSubfile; } subfiledata.writeAddress = offsetOfThisSubfile; data[offset_in_subfiletable_where_address_should_be_written] = (byte)(offsetOfThisSubfile & 0x000000FF); data[offset_in_subfiletable_where_address_should_be_written + 1] = (byte)((offsetOfThisSubfile & 0x0000FF00) >> 8); data[offset_in_subfiletable_where_address_should_be_written + 2] = (byte)((offsetOfThisSubfile & 0x00FF0000) >> 16); data[offset_in_subfiletable_where_address_should_be_written + 3] = (byte)((offsetOfThisSubfile & 0xFF000000) >> 24); if (pos_in_subfiletable == 0x0C) { pos_in_subfiletable += 2; } pos_in_subfiletable += 4; } //now write the subfile file into data if (dontWrite) //if it's just an instance of an existing subfile, don't write a new one { continue; } //compress if needed if (subfiledata.subfileType == 0x04) { subfiledata.filebytes = DSDecmp.NewestProgram.Compress(subfiledata.filebytes, new DSDecmp.Formats.Nitro.LZ10()); } //check for identical files that were already processed if (file.rdtSubfileDataList.IndexOf(subfiledata) > 0 && subfiledata.graphicsType != "palette") { foreach (Byte[] alreadyProcessedFile in AlreadyProcessedFilesAndOffsetsInData.Keys) //if this file is equal to one that was already processed { if (ByteArraysAreEqual(alreadyProcessedFile, subfiledata.filebytes)) { //this file is identical to one that was already processed, so just store a reference to the existing one dontWrite = true; data[offset_in_subfiletable_where_address_should_be_written] = (byte)AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile]; data[offset_in_subfiletable_where_address_should_be_written + 1] = (byte)(AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile] >> 8); data[offset_in_subfiletable_where_address_should_be_written + 2] = (byte)(AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile] >> 16); data[offset_in_subfiletable_where_address_should_be_written + 3] = (byte)(AlreadyProcessedFilesAndOffsetsInData[alreadyProcessedFile] >> 24); break; } } } if (dontWrite) //check again for dontwrite { continue; } //otherwise, write subfiletype and size, then write filebytes AlreadyProcessedFilesAndOffsetsInData.Add(subfiledata.filebytes, offsetOfThisSubfile); //Console.WriteLine(AlreadyProcessedFilesAndOffsetsInData.Count); data.Add((byte)subfiledata.subfileType); data.Add((byte)0); data.Add((byte)(subfiledata.filebytes.Length & 0x000000FF)); data.Add((byte)((subfiledata.filebytes.Length & 0x0000FF00) >> 8)); data.Add((byte)((subfiledata.filebytes.Length & 0x00FF0000) >> 16)); data.Add((byte)((subfiledata.filebytes.Length & 0xFF000000) >> 24)); foreach (Byte b in subfiledata.filebytes) { data.Add(b); } } form1.WriteU32ToArray(nodeTree, basePos + (i * 5) + 1, (uint)offsetOfSubfileTable); //write offset of the subfile table to the last node in the string file.rdtSubfileDataList = backuplist; } else { nodeTree[basePos + (i * 5)] = (byte)node.Nodes[i].Text[0]; form1.WriteU32ToArray(nodeTree, basePos + (i * 5) + 1, 0x11 + (uint)posInNodeTree); AddSubNodesToByteArray(node.Nodes[i], nodeTree); } } }
private void compareArcs_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Title = "Select first arc file"; openFileDialog1.CheckFileExists = true; openFileDialog1.CheckPathExists = true; openFileDialog1.Filter = "1PP archives (*.arc)|*.arc"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { OpenFileDialog openFileDialog2 = new OpenFileDialog(); openFileDialog2.Title = "Select second arc file"; openFileDialog2.CheckFileExists = true; openFileDialog2.CheckPathExists = true; openFileDialog1.Filter = "1PP archives (*.arc)|*.arc"; if (openFileDialog2.ShowDialog() == DialogResult.OK) { arcfile arc1 = new arcfile(); arc1.arcname = Path.GetFileName(openFileDialog1.FileName); arc1.filename = openFileDialog1.FileName; arc1.filebytes = File.ReadAllBytes(openFileDialog1.FileName); arc1.form1 = form1; arc1.ReadArc(); arcfile arc2 = new arcfile(); arc2.arcname = Path.GetFileName(openFileDialog2.FileName); arc2.filename = openFileDialog2.FileName; arc2.filebytes = File.ReadAllBytes(openFileDialog2.FileName); arc2.form1 = form1; arc2.ReadArc(); List <string> report = new List <string>(); foreach (archivedfile f in arc1.archivedfiles) { if (arc2.GetFileWithHash(f.hash) == null) { //if arc2 straight up doesn't have it string evaluatedFilename = f.filename; if (f.filename == "FILENAME_NOT_SET") { evaluatedFilename = f.hash.ToString(); } report.Add("File " + evaluatedFilename + " was present in " + Path.GetFileNameWithoutExtension(arc1.filename) + ", but not " + Path.GetFileNameWithoutExtension(arc2.filename) + "!"); } else { archivedfile equivalent = arc2.GetFileWithHash(f.hash); if (equivalent != null) { f.ReadFile(); equivalent.ReadFile(); if (f.filebytes.Length != equivalent.filebytes.Length) { //if it's present in both, but with different filesizes string evaluatedFilename = f.filename; if (f.filename == "FILENAME_NOT_SET") { evaluatedFilename = f.hash.ToString(); } report.Add("File " + evaluatedFilename + " was present in both archives, but is a different size in " + Path.GetFileNameWithoutExtension(arc2.filename) + "!"); } } } } foreach (archivedfile f in arc2.archivedfiles) { if (arc1.GetFileWithHash(f.hash) == null) { //if arc1 straight up doesn't have it string evaluatedFilename = f.filename; if (f.filename == "FILENAME_NOT_SET") { evaluatedFilename = f.hash.ToString(); } report.Add("File " + evaluatedFilename + " was present in " + Path.GetFileNameWithoutExtension(arc2.filename) + ", but not " + Path.GetFileNameWithoutExtension(arc1.filename) + "!"); } //don't need to do the second part again because it was already two-way } SaveFileDialog saveFileDialog1 = new SaveFileDialog(); saveFileDialog1.Filter = ".txt files (*.txt)|*.txt"; saveFileDialog1.Title = "Save report"; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { File.WriteAllLines(saveFileDialog1.FileName, report.ToArray()); } } } }