diff --git a/CodeWalker.Core/GameFiles/RpfFile.cs b/CodeWalker.Core/GameFiles/RpfFile.cs index 284bf0c..52d292f 100644 --- a/CodeWalker.Core/GameFiles/RpfFile.cs +++ b/CodeWalker.Core/GameFiles/RpfFile.cs @@ -1382,7 +1382,7 @@ namespace CodeWalker.GameFiles { if (child.ParentFileEntry == null) continue;//shouldn't really happen... var cpos = StartPos + (long)child.ParentFileEntry.FileOffset * 512; - child.UpdateStartPos(newpos); + child.UpdateStartPos(cpos); } } } @@ -1517,10 +1517,26 @@ namespace CodeWalker.GameFiles return entry; } - public static RpfFileEntry CreateFile(RpfDirectoryEntry dir, string name, byte[] data) + public static RpfFileEntry CreateFile(RpfDirectoryEntry dir, string name, byte[] data, bool overwrite = true) { - RpfFile parent = dir.File; string namel = name.ToLowerInvariant(); + if (overwrite) + { + foreach (var exfile in dir.Files) + { + if (exfile.NameLower == namel) + { + //file already exists. delete the existing one first! + //this should probably be optimised to just replace the existing one... + //TODO: investigate along with ExploreForm.ReplaceSelected() + DeleteEntry(exfile); + break; + } + } + } + //else fail if already exists..? items with the same name allowed? + + RpfFile parent = dir.File; string fpath = parent.GetPhysicalFilePath(); string rpath = dir.Path + "\\" + namel; if (!File.Exists(fpath)) @@ -1755,6 +1771,43 @@ namespace CodeWalker.GameFiles } + public static bool EnsureValidEncryption(RpfFile file, Func confirm) + { + if (file == null) return false; + + //currently assumes OPEN is the valid encryption type. + //TODO: support other encryption types! + + bool needsupd = false; + var f = file; + List files = new List(); + while (f != null) + { + if (f.Encryption != RpfEncryption.OPEN) + { + if (!confirm(f)) + { + return false; + } + needsupd = true; + } + if (needsupd) + { + files.Add(f); + } + f = f.Parent; + } + + //change encryption types, starting from the root rpf. + files.Reverse(); + foreach (var cfile in files) + { + SetEncryptionType(cfile, RpfEncryption.OPEN); + } + + return true; + } + public static void SetEncryptionType(RpfFile file, RpfEncryption encryption) { file.Encryption = encryption; diff --git a/ExploreForm.Designer.cs b/ExploreForm.Designer.cs index 8f1dc64..1a5f5c3 100644 --- a/ExploreForm.Designer.cs +++ b/ExploreForm.Designer.cs @@ -91,6 +91,12 @@ this.MainSizeColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.MainAttrColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.MainPathColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.EditModeBaseWarningPanel = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label1 = new System.Windows.Forms.Label(); + this.EditModeModsWarningPanel = new System.Windows.Forms.Panel(); + this.pictureBox2 = new System.Windows.Forms.PictureBox(); + this.label2 = new System.Windows.Forms.Label(); this.ListContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.ListContextViewMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ListContextViewHexMenu = new System.Windows.Forms.ToolStripMenuItem(); @@ -116,6 +122,8 @@ this.ListContextReplaceMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ListContextDeleteMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ListContextEditSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.ListContextDefragmentMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.ListContextDefragmentSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ListContextSelectAllMenu = new System.Windows.Forms.ToolStripMenuItem(); this.TreeContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.TreeContextCopyPathMenu = new System.Windows.Forms.ToolStripMenuItem(); @@ -127,14 +135,6 @@ this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog(); this.OpenFileDialog = new System.Windows.Forms.OpenFileDialog(); this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); - this.EditModeBaseWarningPanel = new System.Windows.Forms.Panel(); - this.label1 = new System.Windows.Forms.Label(); - this.pictureBox1 = new System.Windows.Forms.PictureBox(); - this.EditModeModsWarningPanel = new System.Windows.Forms.Panel(); - this.pictureBox2 = new System.Windows.Forms.PictureBox(); - this.label2 = new System.Windows.Forms.Label(); - this.ListContextDefragmentMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.ListContextDefragmentSeparator = new System.Windows.Forms.ToolStripSeparator(); this.MainMenu.SuspendLayout(); this.MainToolbar.SuspendLayout(); this.StatusBar.SuspendLayout(); @@ -142,12 +142,12 @@ this.MainSplitContainer.Panel1.SuspendLayout(); this.MainSplitContainer.Panel2.SuspendLayout(); this.MainSplitContainer.SuspendLayout(); - this.ListContextMenu.SuspendLayout(); - this.TreeContextMenu.SuspendLayout(); this.EditModeBaseWarningPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.EditModeModsWarningPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); + this.ListContextMenu.SuspendLayout(); + this.TreeContextMenu.SuspendLayout(); this.SuspendLayout(); // // MainMenu @@ -175,7 +175,7 @@ // this.FileExitMenu.Name = "FileExitMenu"; this.FileExitMenu.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4))); - this.FileExitMenu.Size = new System.Drawing.Size(152, 22); + this.FileExitMenu.Size = new System.Drawing.Size(134, 22); this.FileExitMenu.Text = "Exit"; this.FileExitMenu.Click += new System.EventHandler(this.FileExitMenu_Click); // @@ -699,6 +699,7 @@ // // MainListView // + this.MainListView.AllowDrop = true; this.MainListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); @@ -723,7 +724,11 @@ this.MainListView.AfterLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.MainListView_AfterLabelEdit); this.MainListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.MainListView_ColumnClick); this.MainListView.ItemActivate += new System.EventHandler(this.MainListView_ItemActivate); + this.MainListView.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.MainListView_ItemDrag); this.MainListView.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.MainListView_RetrieveVirtualItem); + this.MainListView.DragDrop += new System.Windows.Forms.DragEventHandler(this.MainListView_DragDrop); + this.MainListView.DragEnter += new System.Windows.Forms.DragEventHandler(this.MainListView_DragEnter); + this.MainListView.DragLeave += new System.EventHandler(this.MainListView_DragLeave); this.MainListView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainListView_KeyDown); this.MainListView.KeyUp += new System.Windows.Forms.KeyEventHandler(this.MainListView_KeyUp); this.MainListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.MainListView_MouseUp); @@ -754,6 +759,72 @@ this.MainPathColumnHeader.Text = "Path"; this.MainPathColumnHeader.Width = 225; // + // EditModeBaseWarningPanel + // + this.EditModeBaseWarningPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.EditModeBaseWarningPanel.BackColor = System.Drawing.Color.DarkRed; + this.EditModeBaseWarningPanel.Controls.Add(this.pictureBox1); + this.EditModeBaseWarningPanel.Controls.Add(this.label1); + this.EditModeBaseWarningPanel.Location = new System.Drawing.Point(1, 3); + this.EditModeBaseWarningPanel.Name = "EditModeBaseWarningPanel"; + this.EditModeBaseWarningPanel.Size = new System.Drawing.Size(559, 24); + this.EditModeBaseWarningPanel.TabIndex = 1; + // + // pictureBox1 + // + this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); + this.pictureBox1.Location = new System.Drawing.Point(6, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(16, 16); + this.pictureBox1.TabIndex = 1; + this.pictureBox1.TabStop = false; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.BackColor = System.Drawing.Color.Transparent; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.ForeColor = System.Drawing.Color.White; + this.label1.Location = new System.Drawing.Point(25, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(285, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Warning: You are directly editing base game files"; + // + // EditModeModsWarningPanel + // + this.EditModeModsWarningPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.EditModeModsWarningPanel.BackColor = System.Drawing.Color.DarkGreen; + this.EditModeModsWarningPanel.Controls.Add(this.pictureBox2); + this.EditModeModsWarningPanel.Controls.Add(this.label2); + this.EditModeModsWarningPanel.Location = new System.Drawing.Point(1, 28); + this.EditModeModsWarningPanel.Name = "EditModeModsWarningPanel"; + this.EditModeModsWarningPanel.Size = new System.Drawing.Size(559, 24); + this.EditModeModsWarningPanel.TabIndex = 2; + // + // pictureBox2 + // + this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image"))); + this.pictureBox2.Location = new System.Drawing.Point(6, 3); + this.pictureBox2.Name = "pictureBox2"; + this.pictureBox2.Size = new System.Drawing.Size(16, 16); + this.pictureBox2.TabIndex = 1; + this.pictureBox2.TabStop = false; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.BackColor = System.Drawing.Color.Transparent; + this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.ForeColor = System.Drawing.Color.White; + this.label2.Location = new System.Drawing.Point(25, 5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(225, 13); + this.label2.TabIndex = 0; + this.label2.Text = "You are editing files in the mods folder"; + // // ListContextMenu // this.ListContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -783,7 +854,7 @@ this.ListContextDefragmentSeparator, this.ListContextSelectAllMenu}); this.ListContextMenu.Name = "MainContextMenu"; - this.ListContextMenu.Size = new System.Drawing.Size(208, 464); + this.ListContextMenu.Size = new System.Drawing.Size(208, 442); // // ListContextViewMenu // @@ -967,6 +1038,18 @@ this.ListContextEditSeparator.Name = "ListContextEditSeparator"; this.ListContextEditSeparator.Size = new System.Drawing.Size(204, 6); // + // ListContextDefragmentMenu + // + this.ListContextDefragmentMenu.Name = "ListContextDefragmentMenu"; + this.ListContextDefragmentMenu.Size = new System.Drawing.Size(207, 22); + this.ListContextDefragmentMenu.Text = "Defragment Archive..."; + this.ListContextDefragmentMenu.Click += new System.EventHandler(this.ListContextDefragmentMenu_Click); + // + // ListContextDefragmentSeparator + // + this.ListContextDefragmentSeparator.Name = "ListContextDefragmentSeparator"; + this.ListContextDefragmentSeparator.Size = new System.Drawing.Size(204, 6); + // // ListContextSelectAllMenu // this.ListContextSelectAllMenu.Name = "ListContextSelectAllMenu"; @@ -1033,84 +1116,6 @@ // this.OpenFileDialog.Multiselect = true; // - // EditModeBaseWarningPanel - // - this.EditModeBaseWarningPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.EditModeBaseWarningPanel.BackColor = System.Drawing.Color.DarkRed; - this.EditModeBaseWarningPanel.Controls.Add(this.pictureBox1); - this.EditModeBaseWarningPanel.Controls.Add(this.label1); - this.EditModeBaseWarningPanel.Location = new System.Drawing.Point(1, 3); - this.EditModeBaseWarningPanel.Name = "EditModeBaseWarningPanel"; - this.EditModeBaseWarningPanel.Size = new System.Drawing.Size(559, 24); - this.EditModeBaseWarningPanel.TabIndex = 1; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.BackColor = System.Drawing.Color.Transparent; - this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label1.ForeColor = System.Drawing.Color.White; - this.label1.Location = new System.Drawing.Point(25, 5); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(285, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Warning: You are directly editing base game files"; - // - // pictureBox1 - // - this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); - this.pictureBox1.Location = new System.Drawing.Point(6, 3); - this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(16, 16); - this.pictureBox1.TabIndex = 1; - this.pictureBox1.TabStop = false; - // - // EditModeModsWarningPanel - // - this.EditModeModsWarningPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.EditModeModsWarningPanel.BackColor = System.Drawing.Color.DarkGreen; - this.EditModeModsWarningPanel.Controls.Add(this.pictureBox2); - this.EditModeModsWarningPanel.Controls.Add(this.label2); - this.EditModeModsWarningPanel.Location = new System.Drawing.Point(1, 28); - this.EditModeModsWarningPanel.Name = "EditModeModsWarningPanel"; - this.EditModeModsWarningPanel.Size = new System.Drawing.Size(559, 24); - this.EditModeModsWarningPanel.TabIndex = 2; - // - // pictureBox2 - // - this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image"))); - this.pictureBox2.Location = new System.Drawing.Point(6, 3); - this.pictureBox2.Name = "pictureBox2"; - this.pictureBox2.Size = new System.Drawing.Size(16, 16); - this.pictureBox2.TabIndex = 1; - this.pictureBox2.TabStop = false; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.BackColor = System.Drawing.Color.Transparent; - this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.ForeColor = System.Drawing.Color.White; - this.label2.Location = new System.Drawing.Point(25, 5); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(225, 13); - this.label2.TabIndex = 0; - this.label2.Text = "You are editing files in the mods folder"; - // - // ListContextDefragmentMenu - // - this.ListContextDefragmentMenu.Name = "ListContextDefragmentMenu"; - this.ListContextDefragmentMenu.Size = new System.Drawing.Size(207, 22); - this.ListContextDefragmentMenu.Text = "Defragment Archive..."; - this.ListContextDefragmentMenu.Click += new System.EventHandler(this.ListContextDefragmentMenu_Click); - // - // ListContextDefragmentSeparator - // - this.ListContextDefragmentSeparator.Name = "ListContextDefragmentSeparator"; - this.ListContextDefragmentSeparator.Size = new System.Drawing.Size(204, 6); - // // ExploreForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1124,6 +1129,7 @@ this.MainMenuStrip = this.MainMenu; this.Name = "ExploreForm"; this.Text = "RPF Explorer - CodeWalker by dexyfex"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ExploreForm_FormClosed); this.Load += new System.EventHandler(this.ExploreForm_Load); this.MainMenu.ResumeLayout(false); this.MainMenu.PerformLayout(); @@ -1135,14 +1141,14 @@ this.MainSplitContainer.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.MainSplitContainer)).EndInit(); this.MainSplitContainer.ResumeLayout(false); - this.ListContextMenu.ResumeLayout(false); - this.TreeContextMenu.ResumeLayout(false); this.EditModeBaseWarningPanel.ResumeLayout(false); this.EditModeBaseWarningPanel.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.EditModeModsWarningPanel.ResumeLayout(false); this.EditModeModsWarningPanel.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); + this.ListContextMenu.ResumeLayout(false); + this.TreeContextMenu.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); diff --git a/ExploreForm.cs b/ExploreForm.cs index 58c9df8..c5c876e 100644 --- a/ExploreForm.cs +++ b/ExploreForm.cs @@ -925,7 +925,32 @@ namespace CodeWalker MainListView.VirtualListSize = CurrentFiles.Count; } + private void EnsureImportedRpf(RpfFileEntry entry, RpfDirectoryEntry parentrpffldr) + { + if ((entry == null) || (parentrpffldr == null)) return; + var newrpf = parentrpffldr.File?.FindChildArchive(entry); + if (newrpf == null) return; + //an RPF file was imported. add its structure to the UI! + var rootpath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash(); + var tnf = CreateRpfTreeFolder(newrpf, newrpf.Path, rootpath + newrpf.Path); + if (CurrentFolder.Children != null) + { + //make sure any existing (replaced!) one is removed first! + foreach (var child in CurrentFolder.Children) + { + if (child.Path == tnf.Path) + { + CurrentFolder.Children.Remove(child); + child.TreeNode.Remove(); + break; + } + } + } + CurrentFolder.AddChildToHierarchy(tnf); + RecurseMainTreeViewRPF(tnf, AllRpfs); + RecurseAddMainTreeViewNodes(tnf, CurrentFolder.TreeNode); + } private void RefreshMainListView() { @@ -1097,23 +1122,41 @@ namespace CodeWalker { data = entry.File.ExtractFile(entry);//extract an RPF from another. } + else if (!string.IsNullOrEmpty(file.FullPath) && (file.Folder.RpfFile != null)) + { + data = File.ReadAllBytes(file.FullPath); //load RPF file from filesystem + } } - else if (file.File != null) + else if (file.File != null) //load file from RPF { - //load file from RPF if (file.File.File != null) //need the reference to the RPF archive { data = file.File.File.ExtractFile(file.File); } + else + { } } else if (!string.IsNullOrEmpty(file.FullPath)) { - //load file from filesystem - data = File.ReadAllBytes(file.FullPath); + data = File.ReadAllBytes(file.FullPath); //load file from filesystem + } + else + { } + return data; + } + private byte[] GetFileDataCompressResources(MainListItem file) + { + byte[] data = GetFileData(file); + RpfResourceFileEntry rrfe = file.File as RpfResourceFileEntry; + if (rrfe != null) //add resource header if this is a resource file. + { + data = ResourceBuilder.Compress(data); //not completely ideal to recompress it... + data = ResourceBuilder.AddResourceHeader(rrfe, data); } return data; } + private bool CanViewFile(MainListItem item) { if (item == null) return false; @@ -1601,47 +1644,21 @@ namespace CodeWalker - private bool EnsureRpfValidEncryption() + private bool EnsureRpfValidEncryption(RpfFile file = null) { - if (CurrentFolder.RpfFolder == null) return false; + if ((file == null) && (CurrentFolder.RpfFolder == null)) return false; - var rpf = CurrentFolder.RpfFolder.File; + var rpf = file ?? CurrentFolder.RpfFolder.File; - return EnsureRpfValidEncryption(rpf); - } - private bool EnsureRpfValidEncryption(RpfFile rpf) - { if (rpf == null) return false; - bool needsupd = false; - var f = rpf; - List files = new List(); - while (f != null) + var confirm = new Func((f) => { - if (f.Encryption != RpfEncryption.OPEN) - { - var msg = "Archive " + f.Name + " is currently set to " + f.Encryption.ToString() + " encryption.\nAre you sure you want to change this archive to OPEN encryption?\nLoading by the game will require OpenIV.asi."; - if (MessageBox.Show(msg, "Change RPF encryption type", MessageBoxButtons.YesNo) != DialogResult.Yes) - { - return false; - } - needsupd = true; - } - if (needsupd) - { - files.Add(f); - } - f = f.Parent; - } + var msg = "Archive " + f.Name + " is currently set to " + f.Encryption.ToString() + " encryption.\nAre you sure you want to change this archive to OPEN encryption?\nLoading by the game will require OpenIV.asi."; + return (MessageBox.Show(msg, "Change RPF encryption type", MessageBoxButtons.YesNo) == DialogResult.Yes); + }); - //change encryption types, starting from the root rpf. - files.Reverse(); - foreach (var file in files) - { - RpfFile.SetEncryptionType(file, RpfEncryption.OPEN); - } - - return true; + return RpfFile.EnsureValidEncryption(rpf, confirm); } @@ -1776,22 +1793,13 @@ namespace CodeWalker if ((file.Folder == null) || (file.Folder.RpfFile != null)) { - byte[] data = GetFileData(file); + byte[] data = GetFileDataCompressResources(file); if (data == null) { MessageBox.Show("Unable to extract file: " + file.Path); return; } - - RpfResourceFileEntry rrfe = file.File as RpfResourceFileEntry; - if (rrfe != null) //add resource header if this is a resource file. - { - data = ResourceBuilder.Compress(data); //not completely ideal to recompress it... - data = ResourceBuilder.AddResourceHeader(rrfe, data); - } - - SaveFileDialog.FileName = file.Name; if (SaveFileDialog.ShowDialog() == DialogResult.OK) { @@ -1823,19 +1831,13 @@ namespace CodeWalker if ((file.Folder == null) || (file.Folder.RpfFile != null)) { var path = folderpath + file.Name; - var data = GetFileData(file); - if (data == null) - { - errors.AppendLine("Unable to extract file: " + file.Path); - continue; - } try { - RpfResourceFileEntry rrfe = file.File as RpfResourceFileEntry; - if (rrfe != null) //add resource header if this is a resource file. + var data = GetFileDataCompressResources(file); + if (data == null) { - data = ResourceBuilder.Compress(data); //not completely ideal to recompress it... - data = ResourceBuilder.AddResourceHeader(rrfe, data); + errors.AppendLine("Unable to extract file: " + file.Path); + continue; } File.WriteAllBytes(path, data); @@ -1939,19 +1941,13 @@ namespace CodeWalker if ((file.Folder == null) || (file.Folder.RpfFile != null)) { var path = folderpath + file.Name; - var data = GetFileData(file); - if (data == null) - { - errors.AppendLine("Unable to extract file: " + file.Path); - continue; - } try { - RpfResourceFileEntry rrfe = file.File as RpfResourceFileEntry; - if (rrfe != null) //add resource header if this is a resource file. + var data = GetFileDataCompressResources(file); + if (data == null) { - data = ResourceBuilder.Compress(data); - data = ResourceBuilder.AddResourceHeader(rrfe, data); + errors.AppendLine("Unable to extract file: " + file.Path); + continue; } File.WriteAllBytes(path, data); @@ -2099,10 +2095,10 @@ namespace CodeWalker return;//canceled } - try + var fpaths = OpenFileDialog.FileNames; + foreach (var fpath in fpaths) { - var fpaths = OpenFileDialog.FileNames; - foreach (var fpath in fpaths) + try { if (!File.Exists(fpath)) { @@ -2152,26 +2148,13 @@ namespace CodeWalker byte[] data = ResourceBuilder.Build(meta, 2); //meta is RSC V:2 - foreach (var exfile in parentrpffldr.Files) - { - if (exfile.NameLower == fnamel) - { - //file already exists. delete the existing one first! - //this should probably be optimised to just replace the existing one... - //TODO: investigate along with ReplaceSelected() - RpfFile.DeleteEntry(exfile); - break; - } - } - RpfFile.CreateFile(parentrpffldr, fname, data); } - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, "Unable to import file"); - return; + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Unable to import file"); + } } CurrentFolder.ListItems = null; @@ -2183,26 +2166,38 @@ namespace CodeWalker if (!EditMode) return; if (CurrentFolder?.IsSearchResults ?? false) return; - RpfDirectoryEntry parentrpffldr = CurrentFolder.RpfFolder; - if (parentrpffldr == null) - { - MessageBox.Show("No parent RPF folder selected! This shouldn't happen. Refresh the view and try again."); - return; - } - if (!EnsureRpfValidEncryption()) return; - OpenFileDialog.Filter = string.Empty; if (OpenFileDialog.ShowDialog(this) != DialogResult.OK) { return;//canceled } - try + var fpaths = OpenFileDialog.FileNames; + + ImportRaw(fpaths, false);//already checked encryption before the file dialog... + } + private void ImportRaw(string[] fpaths, bool checkEncryption = true) + { + if (!EditMode) return; + if (CurrentFolder?.IsSearchResults ?? false) return; + + RpfDirectoryEntry parentrpffldr = CurrentFolder.RpfFolder; + if (parentrpffldr == null) { - var fpaths = OpenFileDialog.FileNames; - foreach (var fpath in fpaths) + MessageBox.Show("No parent RPF folder selected! This shouldn't happen. Refresh the view and try again."); + return; + } + + if (checkEncryption) + { + if (!EnsureRpfValidEncryption()) return; + } + + foreach (var fpath in fpaths) + { + try { if (!File.Exists(fpath)) { @@ -2211,7 +2206,6 @@ namespace CodeWalker var fi = new FileInfo(fpath); var fname = fi.Name; - var fnamel = fname.ToLowerInvariant(); if (fi.Length > 0x3FFFFFFF) { @@ -2219,54 +2213,20 @@ namespace CodeWalker continue; } + Cursor = Cursors.WaitCursor; + byte[] data = File.ReadAllBytes(fpath); - - foreach (var exfile in parentrpffldr.Files) - { - if (exfile.NameLower == fnamel) - { - //file already exists. delete the existing one first! - //this should probably be optimised to just replace the existing one... - //TODO: investigate along with ReplaceSelected() - RpfFile.DeleteEntry(exfile); - break; - } - } - var entry = RpfFile.CreateFile(parentrpffldr, fname, data); + EnsureImportedRpf(entry, parentrpffldr); //make sure structure is created if an RPF was imported - var newrpf = parentrpffldr.File?.FindChildArchive(entry); - if (newrpf != null) - { - //an RPF file was imported. add its structure to the UI! - var rootpath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash(); - var tnf = CreateRpfTreeFolder(newrpf, newrpf.Path, rootpath + newrpf.Path); - if (CurrentFolder.Children != null) - { - //make sure any existing (replaced!) one is removed first! - foreach (var child in CurrentFolder.Children) - { - if (child.Path == tnf.Path) - { - CurrentFolder.Children.Remove(child); - child.TreeNode.Remove(); - break; - } - } - } - CurrentFolder.AddChildToHierarchy(tnf); - RecurseMainTreeViewRPF(tnf, AllRpfs); - RecurseAddMainTreeViewNodes(tnf, CurrentFolder.TreeNode); - } - + Cursor = Cursors.Default; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Unable to import file"); } - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, "Unable to import file"); - return; } CurrentFolder.ListItems = null; @@ -2641,11 +2601,54 @@ namespace CodeWalker } + + + + private string GetDropFolder() + { + return Path.Combine(Path.GetTempPath(), "CodeWalkerDrop"); + } + private string CreateDropFolder() + { + string drop = GetDropFolder(); + if (!Directory.Exists(drop)) + { + Directory.CreateDirectory(drop); + } + string dir = Path.Combine(drop, Guid.NewGuid().ToString()); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + return dir; + } + private void CleanupDropFolder() + { + string drop = GetDropFolder(); + if (Directory.Exists(drop)) + { + try + { + Directory.Delete(drop, true); //so broken :[ + } + catch { } //not much we can do here... + } + } + + + + + private void ExploreForm_Load(object sender, EventArgs e) { Init(); } + private void ExploreForm_FormClosed(object sender, FormClosedEventArgs e) + { + CleanupDropFolder(); + } + private void MainTreeView_AfterSelect(object sender, TreeViewEventArgs e) { var prev = CurrentFolder; @@ -2822,6 +2825,94 @@ namespace CodeWalker } } + private void MainListView_ItemDrag(object sender, ItemDragEventArgs e) + { + if (MainListView.SelectedIndices.Count <= 0) return; + + var dir = CreateDropFolder(); + var filenames = new List(); + var errors = new List(); + + Cursor = Cursors.WaitCursor; + + for (int i = 0; i < MainListView.SelectedIndices.Count; i++) + { + var idx = MainListView.SelectedIndices[i]; + if ((idx < 0) || (idx >= CurrentFiles.Count)) continue; + var file = CurrentFiles[idx]; + if ((file.Folder == null) || (file.Folder.RpfFile != null)) + { + if (file.FileSize > 0x6400000) //100MB + { + errors.Add(file.Name + " is greater than 100MB, drag-drop for large files is disabled."); + continue; + } + try + { + var data = GetFileDataCompressResources(file); + var filename = Path.Combine(dir, file.Name); + File.WriteAllBytes(filename, data); + filenames.Add(filename); + } + catch (Exception ex) + { + errors.Add(ex.ToString()); + } + } + } + + Cursor = Cursors.Default; + + if (filenames.Count > 0) + { + DataObject dataobj = new DataObject(DataFormats.FileDrop, filenames.ToArray()); + DoDragDrop(dataobj, DragDropEffects.Copy); + } + else + { + if (errors.Count > 0) + { + MessageBox.Show("Errors encountered while dragging:\n" + string.Join("\n", errors.ToArray())); + } + } + + } + + private void MainListView_DragLeave(object sender, EventArgs e) + { + + } + + private void MainListView_DragEnter(object sender, DragEventArgs e) + { + if (!EditMode) return; + if (CurrentFolder?.IsSearchResults ?? false) return; + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + var files = e.Data.GetData(DataFormats.FileDrop) as string[]; + if ((files != null) && (files.Length > 0)) + { + if (!files[0].StartsWith(GetDropFolder(), StringComparison.InvariantCultureIgnoreCase)) //don't dry to drop on ourselves... + { + e.Effect = DragDropEffects.Copy; + } + } + } + } + + private void MainListView_DragDrop(object sender, DragEventArgs e) + { + if (!EditMode) return; + if (CurrentFolder?.IsSearchResults ?? false) return; + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + var files = e.Data.GetData(DataFormats.FileDrop) as string[]; + if ((files == null) || (files.Length <= 0)) return; + if (files[0].StartsWith(GetDropFolder(), StringComparison.InvariantCultureIgnoreCase)) return; //don't dry to drop on ourselves... + ImportRaw(files); + } + } + private void BackButton_ButtonClick(object sender, EventArgs e) { GoBack(); diff --git a/ExploreForm.resx b/ExploreForm.resx index 3cb5ae8..6cf195f 100644 --- a/ExploreForm.resx +++ b/ExploreForm.resx @@ -313,7 +313,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADo - HwAAAk1TRnQBSQFMAgEBGAEAAdgBAAHYAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + HwAAAk1TRnQBSQFMAgEBGAEAAfABAAHwAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAAXADAAEBAQABCAYAARwYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA @@ -450,6 +450,24 @@ AQABAQHAAQEBAAEDAcABAQEAAQEBwAEBAQABAwHAAQEBAAEBAQABAQEAAQcBwAEDAQABAQEAAQEBAAEP AcABAwEAAQEBAAEBAQABDwHAAQMBAAEBAQABAQEAAQ8BwAEDAQABAQHAAQcBAAEPAcABAwEAAQMB4AEP AQABDwHAAQMBAAEHCw== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAAJtJREFUOE+Vj8ENgCAMRdnE1ZzLCwt5cQJvjkDiRfyfUIJQEJo8U2rof5hWOedW + 4CNrHI8XLp3PsXjCPo7Hion3tXm/mwD7KQtJlwVTFmW6MGyRp+MYYD9kUaZjlBaQX4s8XVvQtSjTtQWk + aVGmE4yrBaqFlt6jstDSCX5VBuRj0UtvLSDJopX+R7LAx868X4gGVp5hAQcz4LIxLycs8rg+vnkMAAAA + AElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO + xAAADsQBlSsOGwAAALVJREFUOE/dk70NQjEMhLMHDZuRBZiAadgD6YmGNjNAhaB4okkb/IEtvfgZIaDj + pCvi853y4ySPWmsWDsLmSC1r2xwiLoVlON7aandui+2pIzU0euhV2xNqHtf7y8zouTlcCRm7EFkUBN9s + 8HUNKWbObM03QUOk6XEyAUN05nfEg5eAsAEaIg3i/ZOAl5doiLTpJf72jDoLJZpCg693gwRk8RjlaBo9 + w1EGGvLdZ5pCxA++c0p3WGOjVX9N2kUAAAAASUVORK5CYII= @@ -574,24 +592,6 @@ 152, 56 - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAACbSURBVDhPlY/BDYAgDEXZxNWcywsLeXECb45A4kX8n1CC - UBCaPFNq6H+YVjnnVuAjaxyPFy6dz7F4wj6Ox4qJ97V5v5sA+ykLSZcFUxZlujBskafjGGA/ZFGmY5QW - kF+LPF1b0LUo07UFpGlRphOMqwWqhZbeo7LQ0gl+VQbkY9FLby0gyaKV/keywMfOvF+IBlaeYQEHM+Cy - MS8nLPK4Pr55DAAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAC1SURBVDhP3ZO9DUIxDISzBw2bkQWYgGnYA+mJhjYzQIWg - eKJJG/yBLb34GSGg46Qr4vOd8uMkj1prFg7C5kgta9scIi6FZTje2mp3bovtqSM1NHroVdsTah7X+8vM - 6Lk5XAkZuxBZFATfbPB1DSlmzmzNN0FDpOlxMgFDdOZ3xIOXgLABGiIN4v2TgJeXaIi06SX+9ow6CyWa - QoOvd4MEZPEY5WgaPcNRBhry3WeaQsQPvnNKd1hjo1V/TdpFAAAAAElFTkSuQmCC - - 126