From 0ab4dac353224df4343fcce0c86750c0de48663c Mon Sep 17 00:00:00 2001 From: Sean Miller Date: Sat, 11 Dec 2021 18:10:49 -0800 Subject: [PATCH] Rework of FileBuffers, option to add files to the ISO, and logging of command process outputs --- PBRHex Setup/PBRHex Setup.vdproj | 22 ++++- .../FsysCommands/CreateFileCommand.cs | 5 +- PBRHex/Files/DOL.cs | 5 +- PBRHex/Files/FSYS.cs | 44 ++++------ PBRHex/Files/FileBuffer.cs | 22 +++-- PBRHex/Files/GTX.cs | 29 ++++--- PBRHex/MainWindow.Designer.cs | 34 +++++++- PBRHex/MainWindow.cs | 31 ++++++- PBRHex/MainWindow.resx | 25 +++--- PBRHex/Program.cs | 7 +- PBRHex/Tables/FSYSTable.cs | 85 ++++-------------- PBRHex/Tables/ModelTable.cs | 3 +- PBRHex/Tables/SpriteTable.cs | 41 +++++---- PBRHex/Utils/CommandUtils.cs | 29 ++++--- PBRHex/Utils/FileUtils.cs | 87 ++++++++++--------- 15 files changed, 264 insertions(+), 205 deletions(-) diff --git a/PBRHex Setup/PBRHex Setup.vdproj b/PBRHex Setup/PBRHex Setup.vdproj index 2ae2bae..32ff8aa 100644 --- a/PBRHex Setup/PBRHex Setup.vdproj +++ b/PBRHex Setup/PBRHex Setup.vdproj @@ -824,6 +824,14 @@ "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + } } } "Release" @@ -848,6 +856,14 @@ "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + } } } } @@ -3125,15 +3141,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:PBRHex" - "ProductCode" = "8:{F862B141-98A2-4B8F-A0AC-27BF24540CA4}" - "PackageCode" = "8:{814D39E3-EF1C-4664-A38F-2F514E651F08}" + "ProductCode" = "8:{474EBDA2-7043-4C36-9B60-AC8E24CC2659}" + "PackageCode" = "8:{2D7468B5-FAF1-45C3-B01F-C5E61CC1E8DD}" "UpgradeCode" = "8:{D48A0932-A217-4C66-91CB-5BF77D165DBB}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.0.0" + "ProductVersion" = "8:1.0.3" "Manufacturer" = "8:PBRHex" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/PBRHex/Commands/FsysCommands/CreateFileCommand.cs b/PBRHex/Commands/FsysCommands/CreateFileCommand.cs index feb5eb7..9c3c413 100644 --- a/PBRHex/Commands/FsysCommands/CreateFileCommand.cs +++ b/PBRHex/Commands/FsysCommands/CreateFileCommand.cs @@ -16,8 +16,9 @@ public CreateFileCommand(IFsysEditor editor, FSYS fsys) { } public override bool Execute() { - var file = FileUtils.CreateFile($@"{Program.TempDir}\temp", 0x10); - File = FSYS.AddFile(file); + string path = $@"{Program.TempDir}\temp"; + FileUtils.CreateFile(path, 0x10); + File = FSYS.AddFile(path); Editor.AddFile(File); return false; } diff --git a/PBRHex/Files/DOL.cs b/PBRHex/Files/DOL.cs index a46cd7e..cd01318 100644 --- a/PBRHex/Files/DOL.cs +++ b/PBRHex/Files/DOL.cs @@ -18,10 +18,7 @@ public static class DOL private static FileBuffer Main; public static void Initialize() { - Main = new FileBuffer($@"{Program.ISODir}\sys\main.dol") - { - WorkingDir = FileUtils.CreateWorkspace($@"{Program.ISODir}\sys\main.dol") - }; + Main = new FileBuffer($@"{Program.ISODir}\sys\main.dol"); Comments = new Dictionary(); string path = $@"{Program.UserDir}\comments.txt"; if(File.Exists(path)) { diff --git a/PBRHex/Files/FSYS.cs b/PBRHex/Files/FSYS.cs index 75876d8..032fec6 100644 --- a/PBRHex/Files/FSYS.cs +++ b/PBRHex/Files/FSYS.cs @@ -6,13 +6,11 @@ namespace PBRHex.Files { public class FSYS : FileBuffer { - public List Files { get; private set; } public int FileCount => Files.Count; - public string ExtractedDir { get; set; } + public readonly List Files; - public FSYS(string path, FileBuffer[] files) : base(path) { - Files = new List(files.Length); - Files.AddRange(files); + public FSYS(string path) : base(path) { + Files = new List(FileUtils.DecompressFSYS(Path)); } public FileBuffer GetFile(int id) { @@ -23,37 +21,33 @@ public FileBuffer GetFile(int id) { return null; } - //public FileBuffer AddFile() { - // string outpath = $@"{ExtractedDir}\(null)_{Files.Count.ToString("X8").ToLower()}"; - // FileUtils.CreateFile(outpath, 800); - // var file = new FileBuffer(outpath) { WorkingDir = ExtractedDir }; - // Files.Add(file); - // return file; - //} - - //public FileBuffer AddFile(string inpath) { - // string outpath = $@"{ExtractedDir}\(null)_{Files.Count.ToString("X8").ToLower()}"; - // FileUtils.CopyFile(inpath, outpath); - // var file = new FileBuffer(outpath) { WorkingDir = ExtractedDir }; - // Files.Add(file); - // return file; - //} + public FileBuffer AddFile(string inpath) { + string outpath = $@"{WorkingDir}\files\(null)_{Files.Count:x8}{System.IO.Path.GetExtension(inpath)}"; + FileUtils.CopyFile(inpath, outpath); + var newFile = new FileBuffer(outpath, $@"{WorkingDir}\files"); + newFile.ID = FileUtils.GenerateFileID(this, newFile); + Files.Add(newFile); + return newFile; + } /// /// Copies the supplied file into the archive, returning the newly created file. /// public FileBuffer AddFile(FileBuffer file) { - string path = $@"{ExtractedDir}\(null)_{Files.Count.ToString("X8").ToLower()}"; - var newFile = FileUtils.CreateFile(path, file.GetBufferCopy()); - newFile.WorkingDir = ExtractedDir; - newFile.ID = file.ID; + string path = $@"{WorkingDir}\files\(null)_{Files.Count:x8}"; + FileUtils.CreateFile(path, file.GetBufferCopy()); + var newFile = new FileBuffer(path, $@"{WorkingDir}\files"); + if(file.ID != 0) + newFile.ID = file.ID; + else + newFile.ID = FileUtils.GenerateFileID(this, newFile); Files.Add(newFile); return newFile; } public void RemoveFile(int id) { var file = GetFile(id); - FileUtils.DeleteFile($@"{ExtractedDir}\{file.Name}"); + FileUtils.DeleteFile($@"{WorkingDir}\files\{file.Name}"); Files.Remove(file); } } diff --git a/PBRHex/Files/FileBuffer.cs b/PBRHex/Files/FileBuffer.cs index b2be919..7b68cc3 100644 --- a/PBRHex/Files/FileBuffer.cs +++ b/PBRHex/Files/FileBuffer.cs @@ -16,8 +16,8 @@ public class FileBuffer public LabelType[] LabelMap => MakeLabelMap(); public ReadOnlyLabelDict Labels => new ReadOnlyLabelDict(LabelDict); - public readonly Tape EditHistory; - public readonly Tape LocationHistory; + public Tape EditHistory { get; private set; } + public Tape LocationHistory { get; private set; } public int SaveHead; protected byte[] Buffer { get; set; } @@ -32,7 +32,7 @@ public class FileBuffer /// /// The full path of the item. /// - public readonly string Path; + public string Path { get; private set; } /// /// The path to the containing directory of the item. /// @@ -42,7 +42,7 @@ public class FileBuffer /// /// The path to the file's working directory when editing. /// - public string WorkingDir { get; set; } + public string WorkingDir { get; private set; } public string WorkingPath => $@"{WorkingDir}\{Name}"; private string Key => Extension == "" ? @@ -61,9 +61,19 @@ static FileBuffer() { LoadMetadata(); } - public FileBuffer(string filepath) { - Path = System.IO.Path.GetFullPath(filepath); + public FileBuffer(string path) { + Path = System.IO.Path.GetFullPath(path); + WorkingDir = FileUtils.CreateWorkspace(Path); + Initialize(); + } + + public FileBuffer(string path, string workspace) { + Path = System.IO.Path.GetFullPath(path); + WorkingDir = workspace; + Initialize(); + } + private void Initialize() { Buffer = File.ReadAllBytes(Path); LocationHistory = new Tape(); diff --git a/PBRHex/Files/GTX.cs b/PBRHex/Files/GTX.cs index 12b39d9..1c6420e 100644 --- a/PBRHex/Files/GTX.cs +++ b/PBRHex/Files/GTX.cs @@ -4,8 +4,10 @@ namespace PBRHex.Files { - public class GTX : FileBuffer + public class GTX { + public int ID => Buffer.ID; + public readonly int Width; public readonly int Height; public readonly ImageEncoding Encoding; @@ -13,21 +15,24 @@ public class GTX : FileBuffer private readonly int ImageAddress; private readonly int PaletteAddress; + private readonly FileBuffer Buffer; + + public GTX(FileBuffer buffer) { + Buffer = buffer; - public GTX(string path) : base(path) { - Width = ReadShort(0); - Height = ReadShort(2); - Encoding = (ImageEncoding)ReadInt(8); - PaletteEncoding = (PaletteFormat)ReadInt(0xC); + Width = Buffer.ReadShort(0); + Height = Buffer.ReadShort(2); + Encoding = (ImageEncoding)Buffer.ReadInt(8); + PaletteEncoding = (PaletteFormat)Buffer.ReadInt(0xC); - ImageAddress = ReadInt(0x28); - PaletteAddress = ReadInt(0x48); + ImageAddress = Buffer.ReadInt(0x28); + PaletteAddress = Buffer.ReadInt(0x48); } public int GetImageDataSize() { if(PaletteAddress > 0) return Width * Height; - return ReadInt(0x4c); + return Buffer.ReadInt(0x4c); } public Color GetPixel(int x, int y) { @@ -41,14 +46,16 @@ public Color GetPixel(int x, int y) { block_x * block_height * block_width + (y % block_height) * block_width + (x % block_width); - return GetColorFromPalette(ReadByte(ImageAddress + idx)); + return GetColorFromPalette(Buffer.ReadByte(ImageAddress + idx)); } public Color GetColorFromPalette(int index) { if(PaletteEncoding != PaletteFormat.RGB5A3) throw new NotImplementedException(); - int rgb5a3 = ReadShort(PaletteAddress + index * 2); + int rgb5a3 = Buffer.ReadShort(PaletteAddress + index * 2); return ImageUtils.RGB5A3toColor(rgb5a3); } + + public static explicit operator GTX(FileBuffer file) => new GTX(file); } } diff --git a/PBRHex/MainWindow.Designer.cs b/PBRHex/MainWindow.Designer.cs index 44550c9..9078df9 100644 --- a/PBRHex/MainWindow.Designer.cs +++ b/PBRHex/MainWindow.Designer.cs @@ -42,6 +42,8 @@ private void InitializeComponent() { this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.unpackISOToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.rebuildISOMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.newFSYSMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editorsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.stringEditorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.assemblyEditorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -50,6 +52,7 @@ private void InitializeComponent() { this.dolphinMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.panel1 = new System.Windows.Forms.Panel(); this.messageLabel = new System.Windows.Forms.Label(); + this.selectFilesDialog = new System.Windows.Forms.OpenFileDialog(); this.fileTreeContextMenu.SuspendLayout(); this.headerMenuStrip.SuspendLayout(); this.panel1.SuspendLayout(); @@ -144,6 +147,7 @@ private void InitializeComponent() { this.headerMenuStrip.ImageScalingSize = new System.Drawing.Size(20, 20); this.headerMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.fileToolStripMenuItem, + this.editToolStripMenuItem, this.editorsToolStripMenuItem, this.dolphinMenuItem}); this.headerMenuStrip.Location = new System.Drawing.Point(0, 0); @@ -178,6 +182,21 @@ private void InitializeComponent() { this.rebuildISOMenuItem.Text = "Rebuild ISO"; this.rebuildISOMenuItem.Click += new System.EventHandler(this.RebuildISOButton_Click); // + // editToolStripMenuItem + // + this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.newFSYSMenuItem}); + this.editToolStripMenuItem.Name = "editToolStripMenuItem"; + this.editToolStripMenuItem.Size = new System.Drawing.Size(49, 24); + this.editToolStripMenuItem.Text = "Edit"; + // + // newFSYSMenuItem + // + this.newFSYSMenuItem.Name = "newFSYSMenuItem"; + this.newFSYSMenuItem.Size = new System.Drawing.Size(224, 26); + this.newFSYSMenuItem.Text = "New FSYS"; + this.newFSYSMenuItem.Click += new System.EventHandler(this.NewFSYSMenuItem_Click); + // // editorsToolStripMenuItem // this.editorsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -186,8 +205,8 @@ private void InitializeComponent() { this.dexEditorMenuItem, this.rentalPassEditorToolStripMenuItem}); this.editorsToolStripMenuItem.Name = "editorsToolStripMenuItem"; - this.editorsToolStripMenuItem.Size = new System.Drawing.Size(69, 24); - this.editorsToolStripMenuItem.Text = "Editors"; + this.editorsToolStripMenuItem.Size = new System.Drawing.Size(58, 24); + this.editorsToolStripMenuItem.Text = "Tools"; // // stringEditorMenuItem // @@ -229,7 +248,7 @@ private void InitializeComponent() { this.rentalPassEditorToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.rentalPassEditorToolStripMenuItem.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.rentalPassEditorToolStripMenuItem.Name = "rentalPassEditorToolStripMenuItem"; - this.rentalPassEditorToolStripMenuItem.Size = new System.Drawing.Size(224, 26); + this.rentalPassEditorToolStripMenuItem.Size = new System.Drawing.Size(209, 26); this.rentalPassEditorToolStripMenuItem.Text = "Rental Pass Editor"; this.rentalPassEditorToolStripMenuItem.Click += new System.EventHandler(this.RentalPassEditorMenuItem_Click); // @@ -266,6 +285,12 @@ private void InitializeComponent() { this.messageLabel.TabIndex = 2; this.messageLabel.Text = "Go to \"File > Unpack ISO\" to get started"; // + // selectFilesDialog + // + this.selectFilesDialog.FileName = "Select file(s) to add to the archive"; + this.selectFilesDialog.Multiselect = true; + this.selectFilesDialog.Title = "Select file(s)"; + // // MainWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); @@ -315,6 +340,9 @@ private void InitializeComponent() { private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Label messageLabel; private System.Windows.Forms.ToolStripMenuItem rentalPassEditorToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem newFSYSMenuItem; + private System.Windows.Forms.OpenFileDialog selectFilesDialog; } } diff --git a/PBRHex/MainWindow.cs b/PBRHex/MainWindow.cs index dcbaa76..23af158 100644 --- a/PBRHex/MainWindow.cs +++ b/PBRHex/MainWindow.cs @@ -98,6 +98,7 @@ private void FlashTaskbar() { } private void BuildFileTree() { + FileTree.Nodes.Clear(); BuildFileTreeLoop(Program.ISODir); // expand first nodes fileTreeView.Nodes[0].Expand(); @@ -186,7 +187,6 @@ private void OpenHexEditor(FileBuffer file) { if(result != DialogResult.Yes) return; } - file.WorkingDir = FileUtils.CreateWorkspace(file.Path); hexEditor = new HexEditorWindow(new FileBuffer[] { file }) { Name = file.Name, @@ -372,6 +372,35 @@ private void FileLocationMenuItem_Click(object sender, EventArgs e) { Process.Start(SelectedFilePath); } + // Edit // + + private void NewFSYSMenuItem_Click(object sender, EventArgs e) { + var input = new InputDialog("Name:"); + if(input.ShowDialog() == DialogResult.OK) { + string name = input.Response; + if(FSYSTable.ContainsFile(name)) { + new AlertDialog("A file already exists with that name.").ShowDialog(); + return; + } + if(selectFilesDialog.ShowDialog() == DialogResult.OK) { + FSYSTable.AddFile(name); + string path = FSYSTable.MakePath(name); + FileUtils.CreateFSYS(path); + + var fsys = new FSYS(path); + for(int i = 0; i < selectFilesDialog.FileNames.Length; i++) { + fsys.AddFile(selectFilesDialog.FileNames[i]); + } + var temp = FileUtils.CompressFSYS(fsys); + FileUtils.MoveFile(temp.Path, path); + + BuildFileTree(); + } + } + } + + // Tools // + private void HexEditorMenuItem_Click(object sender, EventArgs e) { OpenHexEditor(new FileBuffer(SelectedFilePath)); } diff --git a/PBRHex/MainWindow.resx b/PBRHex/MainWindow.resx index 418830c..4d5823f 100644 --- a/PBRHex/MainWindow.resx +++ b/PBRHex/MainWindow.resx @@ -121,14 +121,14 @@ 192, 17 - 706, 17 + 873, 17 AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABc - DAAAAk1TRnQBSQFMAgEBBAEAAcgBAAHIAQABFgEAARYBAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + DAAAAk1TRnQBSQFMAgEBBAEAAeABAAHgAQABFgEAARYBAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABWAMAASwDAAEBAQABCAUAASABDxgAAYACAAGAAwACgAEAAYADAAGAAQABgAEAAoACAAPAAQABwAHc AcABAAHwAcoBpgEAATMFAAEzAQABMwEAATMBAAIzAgADFgEAAxwBAAMiAQADKQEAA1UBAANNAQADQgEA AzkBAAGAAXwB/wEAAlAB/wEAAZMBAAHWAQAB/wHsAcwBAAHGAdYB7wEAAdYC5wEAAZABqQGtAgAB/wEz @@ -184,22 +184,15 @@ - 507, 17 + 674, 17 - 352, 17 + 526, 17 17, 17 - - - iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - wwAADsMBx2+oZAAAAE5JREFUOE+dy8EJACAMBMG0Yv9FRu4R0LhqyMH+bizNU6W5+dgr4hMWMUP1wYyi - B2awdsF8zgHmY64FAWl8ji5IY6AeSGshrYVicf4gswkA0sVTYd+XnQAAAABJRU5ErkJggg== - - iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO @@ -230,6 +223,16 @@ AAAASUVORK5CYII= + + + iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + wwAADsMBx2+oZAAAAE5JREFUOE+dy8EJACAMBMG0Yv9FRu4R0LhqyMH+bizNU6W5+dgr4hMWMUP1wYyi + B2awdsF8zgHmY64FAWl8ji5IY6AeSGshrYVicf4gswkA0sVTYd+XnQAAAABJRU5ErkJggg== + + + + 361, 17 + AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA diff --git a/PBRHex/Program.cs b/PBRHex/Program.cs index bf0c766..d796609 100644 --- a/PBRHex/Program.cs +++ b/PBRHex/Program.cs @@ -20,6 +20,7 @@ public static class Program public static readonly string BackupsDir = $@"{UserDir}\backups"; private static int WaitingCount; + private static readonly object LoggerLock = new object(); /// /// The main entry point for the application. @@ -65,8 +66,10 @@ public static void NotifyDone() { } public static void Log(string msg) { - using(var w = File.AppendText($@"{DataDir}\log.txt")) { - w.WriteLine(msg); + lock(LoggerLock) { + using(var w = File.AppendText($@"{DataDir}\log.txt")) { + w.WriteLine(msg); + } } } } diff --git a/PBRHex/Tables/FSYSTable.cs b/PBRHex/Tables/FSYSTable.cs index f0c5877..c14e584 100644 --- a/PBRHex/Tables/FSYSTable.cs +++ b/PBRHex/Tables/FSYSTable.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; -using System.Windows.Forms; using PBRHex.Files; using PBRHex.Utils; @@ -25,9 +23,7 @@ public static void Initialize() { lock(TableLock) { initStart.Set(); string tocPath = $@"{Program.ISODir}\files\GSfsys.toc"; - GSfsys = new FileBuffer(tocPath) { - WorkingDir = FileUtils.CreateWorkspace(tocPath) - }; + GSfsys = new FileBuffer(tocPath); LoadTableOfContents(); LoadedFiles = new Dictionary(); // pre-load common.fsys @@ -56,51 +52,17 @@ private static void LoadTableOfContents() { } } - //private static void Write() { - // Cursor.Current = Cursors.WaitCursor; - // var toc = File.OpenWrite($@"{Program.ISODir}\DATA\files\GSfsys.toc"); - // var paths = Directory.GetFiles( - // $@"{Program.ISODir}\DATA\files", - // "*.fsys", - // SearchOption.AllDirectories).ToList(); - // // alphabetize - // paths.Sort(); + public static string MakePath(string name) { + if(!name.EndsWith(".fsys")) + name += ".fsys"; + string path = $@"{Program.ISODir}\files\{name}"; + return path; + } - // toc.Write(Encoding.ASCII.GetBytes("GLLA"), 0, 4); - // toc.Write(HexUtils.IntToBytes(0x251), 0, 4); - // toc.Write(HexUtils.IntToBytes(paths.Count), 0, 4); - // toc.Seek(0x14, SeekOrigin.Begin); - // toc.Write(HexUtils.IntToBytes(0x20), 0, 4); - // toc.Seek(0x20, SeekOrigin.Begin); - // var offsets = new List(); - // for(int i = 0; i < paths.Count; i++) { - // offsets.Add((int)toc.Position); - // var bytes = Encoding.ASCII.GetBytes(Path.GetFileNameWithoutExtension(paths[i])); - // toc.Write(bytes, 0, bytes.Length); - // toc.WriteByte(0); - // } - // int remainder = 0x10 - (int)toc.Position % 0x10; - // if(remainder != 0x10) - // toc.Write(new byte[remainder], 0, remainder); - // int headers = (int)toc.Position; - // toc.Seek(0x10, SeekOrigin.Begin); - // toc.Write(HexUtils.IntToBytes(headers), 0, 4); - // toc.Seek(headers, SeekOrigin.Begin); - // for(int i = 0; i < offsets.Count; i++) { - // string fname = Path.GetFileName(paths[i]); - // if(!TableOfContents.ContainsKey(fname)) { - // var ids = TableOfContents.Values.ToList(); - // ids.Sort(); - // TableOfContents[fname] = ids.Last() + 1; - // } - // toc.Write(HexUtils.IntToBytes(TableOfContents[fname]), 0, 4); - // toc.Write(HexUtils.IntToBytes(offsets[i]), 0, 4); - // toc.Write(new byte[0x8], 0, 0x8); - // } - // toc.Write(new byte[0x10], 0, 0x10); - // toc.Close(); - // Cursor.Current = Cursors.Default; - //} + public static bool ContainsFile(string name) { + name = Path.GetFileNameWithoutExtension(name); + return NameToID.ContainsKey(name); + } public static FSYS GetFile(string name) { lock(TableLock) { @@ -114,18 +76,11 @@ public static FSYS GetFile(int id) { lock(TableLock) { string name = IDtoName[id]; if(!LoadedFiles.ContainsKey(id)) - LoadedFiles[id] = FileUtils.DecompressFSYS(name); + LoadedFiles[id] = new FSYS(MakePath(name)); return LoadedFiles[id]; } } - public static string MakePath(string name) { - if(!name.EndsWith(".fsys")) - name += ".fsys"; - string path = $@"{Program.ISODir}\files\{name}"; - return path; - } - /// The file ID of the newly added entry. public static int AddFile(string name) { lock(TableLock) { @@ -138,9 +93,9 @@ public static int AddFile(string name) { for(int i = 0; i < count; i++) { string nextName = GSfsys.ReadString(nextNameAddr); int comparison = name.CompareTo(nextName); - if(comparison == 0) + if(comparison == 0) { throw new ArgumentException("A file already exists with that name."); - else if(comparison < 0) { + } else if(comparison < 0) { nameAddr = nextNameAddr; break; } @@ -182,16 +137,10 @@ public static int AddFile(string name) { private static int GenerateFileID() { var rand = new Random(); - int count = GSfsys.ReadInt(0x8), - start = GSfsys.ReadInt(0x10), + int id; + do { id = rand.Next(1, 0xffff); - for(int i = 0; i < count; i++) { - int offset = start + i * 0x10; - if(id == GSfsys.ReadInt(offset)) { - id = rand.Next(1, 0xffff); - i = -1; - } - } + } while(IDtoName.ContainsKey(id)); return id; } diff --git a/PBRHex/Tables/ModelTable.cs b/PBRHex/Tables/ModelTable.cs index 8123c36..9aef008 100644 --- a/PBRHex/Tables/ModelTable.cs +++ b/PBRHex/Tables/ModelTable.cs @@ -232,7 +232,8 @@ public static void SetModel(FileBuffer sdr, Pokemon mon) { int fsysID = GetModelFSYSID(mon), fileID = GetModelFileID(mon); var fsys = FSYSTable.GetFile(fsysID); - FileUtils.ReplaceLZSS(fsys.Name, fileID, sdr); + sdr.ID = fileID; + FileUtils.ReplaceLZSS(fsys.Name, sdr); } public static void AddModelSlot(Pokemon mon) { diff --git a/PBRHex/Tables/SpriteTable.cs b/PBRHex/Tables/SpriteTable.cs index 8b38b43..e0f8adc 100644 --- a/PBRHex/Tables/SpriteTable.cs +++ b/PBRHex/Tables/SpriteTable.cs @@ -41,17 +41,19 @@ public static Image GetFaceSprites(Pokemon mon) { public static void SetBodySprites(Pokemon mon, Image spriteSheet) { int id = GetBodySpriteID(mon); string spritePath = MakeBodySpritePath(id); - var gtx = CreateGTX(spritePath, spriteSheet); - FileUtils.ReplaceLZSS("menu_pokemon", id, gtx); - FileUtils.DeleteFile(gtx.Path); + var temp = CreateGTX(spritePath, spriteSheet); + temp.ID = id; + FileUtils.ReplaceLZSS("menu_pokemon", temp); + FileUtils.DeleteFile(temp.Path); } public static void SetFaceSprites(Pokemon mon, Image spriteSheet) { int id = GetFaceSpriteID(mon); string spritePath = MakeFaceSpritePath(id); - var gtx = CreateGTX(spritePath, spriteSheet); - FileUtils.ReplaceLZSS("menu_face", id, gtx); - FileUtils.DeleteFile(gtx.Path); + var temp = CreateGTX(spritePath, spriteSheet); + temp.ID = id; + FileUtils.ReplaceLZSS("menu_face", temp); + FileUtils.DeleteFile(temp.Path); } public static void AddSpriteSlots(int dex) { @@ -67,19 +69,23 @@ public static void AddSpriteSlots(int dex) { AddBodySpriteSlot(dex, count); AddFaceSpriteSlot(dex, count); - var body = CreateGTX($@"{Program.TempDir}\temp.png", Resources.Unknown_Body); - int bodyID = FileUtils.AddLZSS("menu_pokemon", body); - Resources.Unknown_Body.Save(MakeBodySpritePath(bodyID)); + string path = $@"{Program.TempDir}\temp.png"; - var face = CreateGTX($@"{Program.TempDir}\temp.png", Resources.Unknown_Face); - int faceID = FileUtils.AddLZSS("menu_face", face); - Resources.Unknown_Face.Save(MakeFaceSpritePath(faceID)); + var body = CreateGTX(path, Resources.Unknown_Body); + body.ID = FileUtils.AddLZSS("menu_pokemon", body); + Resources.Unknown_Body.Save(MakeBodySpritePath(body.ID)); + + var face = CreateGTX(path, Resources.Unknown_Face); + face.ID = FileUtils.AddLZSS("menu_face", face); + Resources.Unknown_Face.Save(MakeFaceSpritePath(face.ID)); int offset = start + count * 0x10; - Common0.WriteInt(offset, faceID); // male face - Common0.WriteInt(offset + 4, bodyID); // male body - Common0.WriteInt(offset + 8, faceID); // female face - Common0.WriteInt(offset + 0xc, bodyID); // female body + Common0.WriteInt(offset, face.ID); // male face + Common0.WriteInt(offset + 4, body.ID); // male body + Common0.WriteInt(offset + 8, face.ID); // female face + Common0.WriteInt(offset + 0xc, body.ID); // female body + + FileUtils.DeleteFile(path); } private static void AddBodySpriteSlot(int dex, int index) { @@ -117,7 +123,8 @@ private static FileBuffer CreateGTX(string path, Image image) { image.Save(path); var buf = ImageUtils.ImageToGTX(image, ImageEncoding.RGB5A3); string gtxPath = $@"{Program.TempDir}\temp.gtx"; - return FileUtils.CreateFile(gtxPath, buf); + FileUtils.CreateFile(gtxPath, buf); + return new FileBuffer(gtxPath, Program.TempDir); } private static int GetFaceSpriteIndex(int dex) { diff --git a/PBRHex/Utils/CommandUtils.cs b/PBRHex/Utils/CommandUtils.cs index 66cf97f..09f8f59 100644 --- a/PBRHex/Utils/CommandUtils.cs +++ b/PBRHex/Utils/CommandUtils.cs @@ -42,37 +42,44 @@ public static void UnpackISO(string inpath) { } public static void BuildISO(string outpath) { - Console.WriteLine($@"COPY ""{Program.ISODir}"" ""{outpath}"""); RunProcess($@"{witDir}\wit.exe", $@"COPY ""{Program.ISODir}"" ""{outpath}"""); } public static Process RunDolphin() { - return RunProcess($"Dolphin.exe", + return RunProcess("Dolphin.exe", $@"-b -e ""{Program.ISODir}\sys\main.dol""", false); } private static Process RunProcess(string path, string args, bool wait = true) { - Process p; - ProcessStartInfo info = new ProcessStartInfo(path, args) + var info = new ProcessStartInfo(path, args) { CreateNoWindow = true, UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, WorkingDirectory = Path.GetDirectoryName(path) }; + Program.NotifyWaiting(); + Process process = new Process() + { + StartInfo = info, + EnableRaisingEvents = true + }; + process.OutputDataReceived += (s, e) => { Program.Log(e.Data); }; + process.ErrorDataReceived += (s, e) => { Program.Log(e.Data); }; try { - Program.NotifyWaiting(); - p = Process.Start(info); - p.EnableRaisingEvents = true; + process.Start(); + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); if(wait) - p.WaitForExit(); - } - finally { + process.WaitForExit(); + } finally { Program.NotifyDone(); } - return p; + return process; } } } diff --git a/PBRHex/Utils/FileUtils.cs b/PBRHex/Utils/FileUtils.cs index c31c050..00ee218 100644 --- a/PBRHex/Utils/FileUtils.cs +++ b/PBRHex/Utils/FileUtils.cs @@ -34,13 +34,29 @@ public static void MoveContents(string inpath, string outpath, bool deleteSource DeleteDirectory(inpath); } - public static FileBuffer CreateFile(string path, int size) { - return CreateFile(path, new byte[size]); + /// Path at which to create the file + /// Initial size of the file + public static void CreateFile(string path, int size) { + CreateFile(path, new byte[size]); } - public static FileBuffer CreateFile(string path, byte[] bytes) { + /// Path at which to create the file + /// Data to initialize the file with + public static void CreateFile(string path, byte[] bytes) { File.WriteAllBytes(path, bytes); - return new FileBuffer(path); + } + + public static void CreateFSYS(string path) { + byte[] bytes = new byte[] + { + 0x46, 0x53, 0x59, 0x53, 0x00, 0x00, 0x02, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + CreateFile(path, bytes); } public static void DeleteFile(string path) { @@ -63,6 +79,7 @@ public static void RenameFile(string inpath, string name) { MoveFile(inpath, $@"{Path.GetDirectoryName(inpath)}\{name}"); } + /// The path of the newly created workspace public static string CreateWorkspace(string inpath) { string fname = Path.GetFileName(inpath), workspace = $@"{Program.TempDir}\{fname}"; @@ -116,21 +133,22 @@ public static void WriteToISO(FileBuffer file) { CopyFile(file.WorkingPath, file.Path); } - public static void ReplaceLZSS(string name, int id, FileBuffer file) { + /// The name of the FSYS in which to replace + /// A FileBuffer representing the replacement file + public static void ReplaceLZSS(string name, FileBuffer file) { FSYSTable.WriteFile(name); - string fsysPath = FSYSTable.MakePath(name), - workspace = CreateWorkspace(fsysPath), - indir = $@"{workspace}\files", - outdir = $@"{workspace}\lzss"; + string fsysPath = FSYSTable.MakePath(name); + var fsys = new FileBuffer(fsysPath); + string indir = $@"{ fsys.WorkingDir}\files", + outdir = $@"{fsys.WorkingDir}\lzss"; CreateFile($@"{indir}\{file.Name}", file.GetBufferCopy()); CommandUtils.CompressLZSSFiles(indir, outdir); - var fsys = new FileBuffer(fsysPath) { WorkingDir = workspace }; int count = fsys.ReadInt(0xc), lzssAddrList = fsys.ReadInt(fsys.ReadInt(0x18)), index = -1, lzssHeaderAddr = 0; for(int i = 0; i < count; i++) { int address = fsys.ReadInt(lzssAddrList + 4 * i); - if(fsys.ReadInt(address) == id) { + if(fsys.ReadInt(address) == file.ID) { lzssHeaderAddr = address; index = i; break; @@ -180,13 +198,12 @@ public static void ReplaceLZSS(string name, int id, FileBuffer file) { /// The file ID of the new LZSS. public static int AddLZSS(string name, FileBuffer file) { FSYSTable.WriteFile(name); - string fsysPath = FSYSTable.MakePath(name), - workspace = CreateWorkspace(fsysPath), - indir = $@"{workspace}\files", - outdir = $@"{workspace}\lzss"; + string fsysPath = FSYSTable.MakePath(name); + var fsys = new FileBuffer(fsysPath); + string indir = $@"{fsys.WorkingDir}\files", + outdir = $@"{fsys.WorkingDir}\lzss"; CreateFile($@"{indir}\{file.Name}", file.GetBufferCopy()); CommandUtils.CompressLZSSFiles(indir, outdir); - var fsys = new FileBuffer(fsysPath) { WorkingDir = workspace }; var lzss = File.ReadAllBytes(Directory.GetFiles(outdir)[0]); int count = fsys.ReadInt(0xc); // add row before file names if no room for new pointer @@ -243,14 +260,13 @@ public static int AddLZSS(string name, FileBuffer file) { int dataAddr = (prevDataAddr + prevDataSize + 0xf) / 0x10 * 0x10 + 0x10, size = (lzss.Length + 0xf) / 0x10 * 0x10 + 0x20; // fill in newly added header - var ftype = TypeFromExtension(file.Extension); - int id = GenerateFileID(fsys, ftype); + int id = GenerateFileID(fsys, file); fsys.WriteInt(headerAddr, id); fsys.WriteInt(headerAddr + 4, dataAddr); fsys.WriteInt(headerAddr + 8, file.Size); fsys.WriteInt(headerAddr + 0xc, 0x80000000); fsys.WriteInt(headerAddr + 0x14, lzss.Length); - fsys.WriteInt(headerAddr + 0x20, (int)ftype); + fsys.WriteInt(headerAddr + 0x20, (int)TypeFromExtension(file.Extension)); fsys.WriteInt(headerAddr + 0x24, nameAddr); // insert new lzss data fsys.InsertRange(dataAddr - 0x10, size); @@ -267,7 +283,7 @@ public static int AddLZSS(string name, FileBuffer file) { return id; } - private static int GenerateFileID(FileBuffer fsys, FileType type) { + public static int GenerateFileID(FileBuffer fsys, FileBuffer file) { var rand = new Random(); int count = fsys.ReadInt(0xc), lzssListAddr = fsys.ReadInt(fsys.ReadInt(0x18)), @@ -279,13 +295,12 @@ private static int GenerateFileID(FileBuffer fsys, FileType type) { i = -1; } } - return id * 0x10000 + (int)type * 0x200; + return id * 0x10000 + (int)TypeFromExtension(file.Extension) * 0x200; } - /// The path to the folder containing the extracted files. - public static FSYS DecompressFSYS(string name) { - string path = FSYSTable.MakePath(name), - outdir = $@"{CreateWorkspace(path)}\files"; + /// An array of FileBuffers of the extracted files. + public static FileBuffer[] DecompressFSYS(string path) { + string outdir = $@"{CreateWorkspace(path)}\files"; CommandUtils.ExtractFSYS(path, outdir); var paths = Directory.GetFiles(outdir).ToList(); @@ -314,26 +329,18 @@ public static FSYS DecompressFSYS(string name) { string withExt = $"{paths[i]}{ExtensionFromType((FileType)ftype)}"; File.Move(paths[i], withExt); paths[i] = withExt; - if((FileType)ftype == FileType.GTX) - files[i] = new GTX(paths[i]); - else - files[i] = new FileBuffer(paths[i]); - files[i].ID = id; - files[i].WorkingDir = outdir; + files[i] = new FileBuffer(paths[i], outdir) { ID = id }; } file.Close(); - return new FSYS(path, files) - { - WorkingDir = Path.GetDirectoryName(outdir), - ExtractedDir = outdir - }; + return files; } - /// A FileBuffer for the resulting .fsys file. + /// The path of the newly created .fsys file. public static FileBuffer CompressFSYS(FSYS fsys) { // recompress LZSS files - string outdir = $@"{fsys.WorkingDir}\lzss"; - CommandUtils.CompressLZSSFiles(fsys.ExtractedDir, outdir); + string indir = $@"{fsys.WorkingDir}\files", + outdir = $@"{fsys.WorkingDir}\lzss"; + CommandUtils.CompressLZSSFiles(indir, outdir); string[] paths = Directory.GetFiles(outdir); // would probably be a good idea NOT to hold all of them in memory at the same time... @@ -440,7 +447,7 @@ public static FileBuffer CompressFSYS(FSYS fsys) { outfile.Write(Encoding.ASCII.GetBytes("FSYS"), 0, 4); outfile.Close(); - return new FileBuffer(outpath) { WorkingDir = outdir }; + return new FileBuffer(outpath, outdir); } } }