diff --git a/ExploreForm.Designer.cs b/ExploreForm.Designer.cs index 5a57795..85fc40d 100644 --- a/ExploreForm.Designer.cs +++ b/ExploreForm.Designer.cs @@ -127,6 +127,12 @@ 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.MainMenu.SuspendLayout(); this.MainToolbar.SuspendLayout(); this.StatusBar.SuspendLayout(); @@ -136,6 +142,10 @@ 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.SuspendLayout(); // // MainMenu @@ -658,6 +668,8 @@ // MainSplitContainer.Panel2 // this.MainSplitContainer.Panel2.Controls.Add(this.MainListView); + this.MainSplitContainer.Panel2.Controls.Add(this.EditModeBaseWarningPanel); + this.MainSplitContainer.Panel2.Controls.Add(this.EditModeModsWarningPanel); this.MainSplitContainer.Size = new System.Drawing.Size(876, 516); this.MainSplitContainer.SplitterDistance = 309; this.MainSplitContainer.TabIndex = 3; @@ -717,7 +729,7 @@ // MainNameColumnHeader // this.MainNameColumnHeader.Text = "Name"; - this.MainNameColumnHeader.Width = 225; + this.MainNameColumnHeader.Width = 219; // // MainTypeColumnHeader // @@ -1017,6 +1029,72 @@ // 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"; + // // ExploreForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1043,6 +1121,12 @@ 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.ResumeLayout(false); this.PerformLayout(); @@ -1147,5 +1231,11 @@ private System.Windows.Forms.ToolStripMenuItem ListContextNewRpfArchiveMenu; private System.Windows.Forms.ToolStripSeparator toolStripSeparator10; private System.Windows.Forms.ToolStripButton EditModeButton; + private System.Windows.Forms.Panel EditModeBaseWarningPanel; + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Panel EditModeModsWarningPanel; + private System.Windows.Forms.PictureBox pictureBox2; + private System.Windows.Forms.Label label2; } } \ No newline at end of file diff --git a/ExploreForm.cs b/ExploreForm.cs index 9d6217c..c73e040 100644 --- a/ExploreForm.cs +++ b/ExploreForm.cs @@ -405,6 +405,7 @@ namespace CodeWalker //called after the CurrentFolder and CurrentFiles have changed. UpdateNavigateUI(); + EnsureEditModeWarning(); if (!HistoryNavigating) //only do this if not currently navigating forward or back { @@ -1132,11 +1133,21 @@ namespace CodeWalker private byte[] GetFileData(MainListItem file) { byte[] data = null; - if (file.File != null) + if (file.Folder != null) + { + var entry = file.Folder.RpfFile?.ParentFileEntry; + if (entry != null) + { + data = entry.File.ExtractFile(entry);//extract an RPF from another. + } + } + else if (file.File != null) { //load file from RPF - if (file.File.File == null) return null; //no RPF file? go no further - data = file.File.File.ExtractFile(file.File); + if (file.File.File != null) //need the reference to the RPF archive + { + data = file.File.File.ExtractFile(file.File); + } } else if (!string.IsNullOrEmpty(file.FullPath)) { @@ -1189,6 +1200,7 @@ namespace CodeWalker case FileTypeAction.ViewYmap: case FileTypeAction.ViewYtyp: case FileTypeAction.ViewJPso: + case FileTypeAction.ViewCut: return true; } return false; @@ -1515,22 +1527,28 @@ namespace CodeWalker bool isitem = false; bool isfile = false; bool isfolder = false; + bool isarchive = false; bool isfilesys = false; bool issearch = CurrentFolder?.IsSearchResults ?? false; bool canview = false; bool canexportxml = false; + bool canextract = false; bool canimport = EditMode && (CurrentFolder?.RpfFolder != null) && !issearch; + bool cancreate = EditMode && !issearch; bool canedit = false; if (item != null) { + var entry = item.GetRpfEntry(); + isitem = true; + isfilesys = (entry == null); + isarchive = (item.Folder?.RpfFile != null); isfolder = (item.Folder != null); - isfilesys = (item.File == null) && (item.Folder == null); + isfile = !isfolder; canview = CanViewFile(item); canexportxml = CanExportXml(item); - isitem = true; - isfile = !isfolder; canedit = EditMode && !issearch; + canextract = isfile || (isarchive && !isfilesys); } @@ -1538,13 +1556,13 @@ namespace CodeWalker ListContextViewHexMenu.Enabled = isfile; ListContextExportXmlMenu.Enabled = canexportxml; - ListContextExtractRawMenu.Enabled = isfile; + ListContextExtractRawMenu.Enabled = canextract; ListContextExtractUncompressedMenu.Enabled = isfile; - ListContextNewMenu.Visible = EditMode; + ListContextNewMenu.Visible = cancreate; ListContextImportRawMenu.Visible = canimport; ListContextImportXmlMenu.Visible = canimport; - ListContextImportSeparator.Visible = EditMode; + ListContextImportSeparator.Visible = cancreate; ListContextCopyMenu.Enabled = isfile; ListContextCopyPathMenu.Enabled = isitem; @@ -1583,9 +1601,22 @@ namespace CodeWalker EditModeButton.Checked = enable; MainListView.LabelEdit = enable; + EnsureEditModeWarning(); } + private void EnsureEditModeWarning() + { + bool show = EditMode && !CurrentFolder.Path.ToLowerInvariant().StartsWith("mods"); + int gap = 3; + int bot = MainListView.Bottom; + EditModeBaseWarningPanel.Top = gap; + EditModeModsWarningPanel.Top = gap; + EditModeModsWarningPanel.Visible = false; + + MainListView.Top = show ? EditModeBaseWarningPanel.Bottom + gap : gap; + MainListView.Height = bot - MainListView.Top; + } @@ -1605,6 +1636,50 @@ namespace CodeWalker + + private bool EnsureRpfValidEncryption() + { + if (CurrentFolder.RpfFolder == null) return false; + + var rpf = CurrentFolder.RpfFolder.File; + + if (rpf == null) return false; + + bool needsupd = false; + var f = rpf; + List files = new List(); + while (f != null) + { + 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; + } + + //change encryption types, starting from the root rpf. + files.Reverse(); + foreach (var file in files) + { + RpfFile.SetEncryptionType(file, RpfEncryption.OPEN); + } + + return true; + } + + + + + private void ViewSelected() { for (int i = 0; i < MainListView.SelectedIndices.Count; i++) @@ -1731,7 +1806,8 @@ namespace CodeWalker var idx = MainListView.SelectedIndices[0]; if ((idx < 0) || (idx >= CurrentFiles.Count)) return; var file = CurrentFiles[idx]; - if (file.Folder == null) + + if ((file.Folder == null) || (file.Folder.RpfFile != null)) { byte[] data = GetFileData(file); if (data == null) @@ -1744,7 +1820,7 @@ namespace CodeWalker RpfResourceFileEntry rrfe = file.File as RpfResourceFileEntry; if (rrfe != null) //add resource header if this is a resource file. { - data = ResourceBuilder.Compress(data); + data = ResourceBuilder.Compress(data); //not completely ideal to recompress it... data = ResourceBuilder.AddResourceHeader(rrfe, data); } @@ -1777,7 +1853,7 @@ namespace CodeWalker var idx = MainListView.SelectedIndices[i]; if ((idx < 0) || (idx >= CurrentFiles.Count)) continue; var file = CurrentFiles[idx]; - if (file.Folder == null) + if ((file.Folder == null) || (file.Folder.RpfFile != null)) { var path = folderpath + file.Name; var data = GetFileData(file); @@ -1791,7 +1867,7 @@ namespace CodeWalker RpfResourceFileEntry rrfe = file.File as RpfResourceFileEntry; if (rrfe != null) //add resource header if this is a resource file. { - data = ResourceBuilder.Compress(data); + data = ResourceBuilder.Compress(data); //not completely ideal to recompress it... data = ResourceBuilder.AddResourceHeader(rrfe, data); } @@ -1893,7 +1969,7 @@ namespace CodeWalker foreach (var file in CurrentFiles) { - if (file.Folder == null) + if ((file.Folder == null) || (file.Folder.RpfFile != null)) { var path = folderpath + file.Name; var data = GetFileData(file); @@ -1950,6 +2026,8 @@ namespace CodeWalker { if (CurrentFolder.RpfFolder != null) { + if (!EnsureRpfValidEncryption()) return; + //create new directory entry in the RPF. newdir = RpfFile.CreateDirectory(CurrentFolder.RpfFolder, fname); @@ -2007,6 +2085,8 @@ namespace CodeWalker { if (CurrentFolder.RpfFolder != null) { + if (!EnsureRpfValidEncryption()) return; + //adding a new RPF as a child of another newrpf = RpfFile.CreateNew(CurrentFolder.RpfFolder, fname, encryption); } @@ -2043,6 +2123,9 @@ namespace CodeWalker return; } + if (!EnsureRpfValidEncryption()) return; + + OpenFileDialog.Filter = "XML Files|*.xml"; if (OpenFileDialog.ShowDialog(this) != DialogResult.OK) { @@ -2140,6 +2223,9 @@ namespace CodeWalker return; } + if (!EnsureRpfValidEncryption()) return; + + OpenFileDialog.Filter = string.Empty; if (OpenFileDialog.ShowDialog(this) != DialogResult.OK) { @@ -2181,7 +2267,32 @@ namespace CodeWalker } } - RpfFile.CreateFile(parentrpffldr, fname, data); + var entry = RpfFile.CreateFile(parentrpffldr, fname, data); + + + var newrpf = parentrpffldr.File?.FindChildArchive(entry); + if (newrpf != null) + { + //an RPF file was imported. add its structure to the UI! + var rootpath = GetRootPath(); + 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); + } } } @@ -2281,6 +2392,8 @@ namespace CodeWalker } if (entry != null) { + if (!EnsureRpfValidEncryption()) return; + //renaming an entry in an RPF RpfFile.RenameEntry(entry, newname); } @@ -2327,6 +2440,9 @@ namespace CodeWalker if (MainListView.SelectedIndices.Count != 1) return; MessageBox.Show("ReplaceSelected TODO..."); //delete the selected items, and replace with... choose + + //if (!EnsureRpfEncryptionType()) return; + } private void DeleteSelected() { @@ -2368,6 +2484,8 @@ namespace CodeWalker if (parent.RpfFolder != null) { //delete an item in an RPF. + if (!EnsureRpfValidEncryption()) return; + RpfEntry entry = item.GetRpfEntry(); RpfFile.DeleteEntry(entry); @@ -3251,6 +3369,7 @@ namespace CodeWalker { FileSize = fld.RpfFile.FileSize; FileSizeText = TextUtil.GetBytesReadable(FileSize); + Attributes += fld.RpfFile.Encryption.ToString() + " encryption"; } else { diff --git a/ExploreForm.resx b/ExploreForm.resx index 3fa8922..f35d760 100644 --- a/ExploreForm.resx +++ b/ExploreForm.resx @@ -271,6 +271,16 @@ e2d2SZBn3BDEyPiVG5X23Ap3LtwYqxPDuBkxUEmGNWnPzTCEn1GZjBBcYawROqpiopbZ8v/CtN9mmB+9 1vZY1yV7KT9+37JAwB1LBeyfTv8N11OX0LGtniroCF2hd2L+f3A9qqp2iWbL30hjPP3/CJi+jvVtWwLw A4Rmgl76+inbAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADVSURBVDhPpVIxDoMwDORJfQN7pI5hz1pmytSJ7/EFhrYZ + MqSVgDXlIhslaoga9aQTsn1nOyFVDsuynNd1HTe6gCPyJDnGJrpN0+T6vnd1Xe9EjDzqJP0GJkAkhIjM + TOSpSXoTrMmTu+7qHvene9m3/7aX1udRh44sMXBWnsZmJmKuQUeWGFiPRaGZKaXMN/hrg3meTygopbyo + 6A7IbIdh2KekmPwLR+amaaI4+Q6OzDiGMcafNWD8EnNmrbVFnaRppBr8bGaETYrNDG4CFpsZMJaZq+oD + NQar60zqQI0AAAAASUVORK5CYII= @@ -290,16 +300,6 @@ lVY67e7NJiI/2QxXrEetVVZsAY5938U5NzUbthbgknMW7735iOnYsB0AqBXXlJL5jOnYsDUBqA1uMcbh mYyuz6aAU/M9hKDP3GR0ffYegNrwXEpRADdZr5+aAlB7UAB3j1V/Anh1j1UD4Fub4YrN8HPL9gAVE1vf J6IiRgAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADVSURBVDhPpVIxDoMwDORJfQN7pI5hz1pmytSJ7/EFhrYZ - MqSVgDXlIhslaoga9aQTsn1nOyFVDsuynNd1HTe6gCPyJDnGJrpN0+T6vnd1Xe9EjDzqJP0GJkAkhIjM - TOSpSXoTrMmTu+7qHvene9m3/7aX1udRh44sMXBWnsZmJmKuQUeWGFiPRaGZKaXMN/hrg3meTygopbyo - 6A7IbIdh2KekmPwLR+amaaI4+Q6OzDiGMcafNWD8EnNmrbVFnaRppBr8bGaETYrNDG4CFpsZMJaZq+oD - NQar60zqQI0AAAAASUVORK5CYII= @@ -313,7 +313,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADo - HwAAAk1TRnQBSQFMAgEBGAEAAdABAAHQAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + HwAAAk1TRnQBSQFMAgEBGAEAAdgBAAHYAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAAXADAAEBAQABCAYAARwYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA @@ -450,6 +450,24 @@ AQABAQHAAQEBAAEDAcABAQEAAQEBwAEBAQABAwHAAQEBAAEBAQABAQEAAQcBwAEDAQABAQEAAQEBAAEP AcABAwEAAQEBAAEBAQABDwHAAQMBAAEBAQABAQEAAQ8BwAEDAQABAQHAAQcBAAEPAcABAwEAAQMB4AEP AQABDwHAAQMBAAEHCw== + + + + + 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 diff --git a/GameFiles/Resources/RpfFile.cs b/GameFiles/Resources/RpfFile.cs index 287a4d0..fc2138a 100644 --- a/GameFiles/Resources/RpfFile.cs +++ b/GameFiles/Resources/RpfFile.cs @@ -885,15 +885,6 @@ namespace CodeWalker.GameFiles //entries may have been updated, so need to do this after ensuring header space var entriesdata = GetHeaderEntriesData(); - //now there's enough space, it's safe to write the header data... - bw.BaseStream.Position = StartPos; - - bw.Write(Version); - bw.Write(EntryCount); - bw.Write(NamesLength); - bw.Write((uint)Encryption); - - //FileSize = ... //need to make sure this is updated for NG encryption... switch (Encryption) { @@ -916,6 +907,13 @@ namespace CodeWalker.GameFiles break; } + //now there's enough space, it's safe to write the header data... + bw.BaseStream.Position = StartPos; + + bw.Write(Version); + bw.Write(EntryCount); + bw.Write(NamesLength); + bw.Write((uint)Encryption); bw.Write(entriesdata); bw.Write(namesdata); @@ -1337,7 +1335,7 @@ namespace CodeWalker.GameFiles } } - private RpfFile FindChildArchive(RpfFileEntry f) + public RpfFile FindChildArchive(RpfFileEntry f) { RpfFile c = null; if (Children != null) @@ -1442,8 +1440,8 @@ namespace CodeWalker.GameFiles { //create a new directory inside the given parent dir - string namel = name.ToLowerInvariant(); RpfFile parent = dir.File; + string namel = name.ToLowerInvariant(); string fpath = parent.GetPhysicalFilePath(); string rpath = dir.Path + "\\" + namel; @@ -1486,8 +1484,9 @@ namespace CodeWalker.GameFiles public static RpfFileEntry CreateFile(RpfDirectoryEntry dir, string name, byte[] data) { RpfFile parent = dir.File; + string namel = name.ToLowerInvariant(); string fpath = parent.GetPhysicalFilePath(); - string rpath = dir.Path + "\\" + name; + string rpath = dir.Path + "\\" + namel; if (!File.Exists(fpath)) { throw new Exception("Root RPF file " + fpath + " does not exist!"); @@ -1497,8 +1496,15 @@ namespace CodeWalker.GameFiles RpfFileEntry entry = null; uint len = (uint)data.Length; - //check if this is RSC7 data, import as a resource if it is... - if ((len >= 16) && (BitConverter.ToUInt32(data, 0) == 0x37435352)) + + bool isrpf = false; + uint hdr = 0; + if (len >= 16) + { + hdr = BitConverter.ToUInt32(data, 0); + } + + if (hdr == 0x37435352) //'RSC7' { //RSC header is present... import as resource var rentry = new RpfResourceFileEntry(); @@ -1519,16 +1525,20 @@ namespace CodeWalker.GameFiles entry = rentry; } + if (namel.EndsWith(".rpf") && (hdr == 0x52504637)) //'RPF7' + { + isrpf = true; + } if (entry == null) { //no RSC7 header present, import as a binary file. - var compressed = CompressBytes(data); + var compressed = isrpf ? data : CompressBytes(data); var bentry = new RpfBinaryFileEntry(); bentry.EncryptionType = 0;//TODO: binary encryption bentry.IsEncrypted = false; bentry.FileUncompressedSize = (uint)data.Length; - bentry.FileSize = (uint)compressed.Length; + bentry.FileSize = isrpf ? 0 : (uint)compressed.Length; if (bentry.FileSize > 0xFFFFFF) { bentry.FileSize = 0; @@ -1577,6 +1587,25 @@ namespace CodeWalker.GameFiles } + if (isrpf) + { + //importing a raw RPF archive. create the new RpfFile object, and read its headers etc. + RpfFile file = new RpfFile(name, rpath, data.LongLength); + file.Parent = parent; + file.ParentFileEntry = entry as RpfBinaryFileEntry; + file.StartPos = parent.StartPos + (entry.FileOffset * 512); + parent.Children.Add(file); + + using (var fstream = File.OpenRead(fpath)) + { + using (var br = new BinaryReader(fstream)) + { + fstream.Position = file.StartPos; + file.ScanStructure(br, null, null); + } + } + } + return entry; } @@ -1690,6 +1719,19 @@ namespace CodeWalker.GameFiles } + public static void SetEncryptionType(RpfFile file, RpfEncryption encryption) + { + file.Encryption = encryption; + string fpath = file.GetPhysicalFilePath(); + using (var fstream = File.Open(fpath, FileMode.Open, FileAccess.ReadWrite)) + { + using (var bw = new BinaryWriter(fstream)) + { + file.WriteHeader(bw); + } + } + } + private static string GetParentPath(string path) diff --git a/Todo.txt b/Todo.txt index 09d0048..e7a34db 100644 --- a/Todo.txt +++ b/Todo.txt @@ -102,7 +102,10 @@ done: [v.29] entitySets - like mapDataGroups but for interiors..... in Mlo data -delete key - delete item! +World view - delete key - delete item! +RPF Explorer Edit mode +AWC audio player (dav90 WIP) +Invert mouse option [v.28]