mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 00:43:00 +08:00
RPF Explorer Edit mode
This commit is contained in:
parent
81daf0c23e
commit
65c549840f
73
ExploreForm.Designer.cs
generated
73
ExploreForm.Designer.cs
generated
@ -59,6 +59,7 @@
|
||||
this.ViewListMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ViewDetailsMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsBinSearchMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsRpfBrowserMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ToolsOptionsMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@ -72,6 +73,8 @@
|
||||
this.LocationTextBox = new CodeWalker.WinForms.ToolStripSpringTextBox();
|
||||
this.GoButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.RefreshButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.EditModeButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.SearchTextBox = new System.Windows.Forms.ToolStripTextBox();
|
||||
this.SearchButton = new System.Windows.Forms.ToolStripSplitButton();
|
||||
@ -97,6 +100,9 @@
|
||||
this.ListContextExtractUncompressedMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ListContextExtractAllMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ListContextNewMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ListContextNewFolderMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ListContextNewRpfArchiveMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ListContextImportXmlMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ListContextImportRawMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ListContextImportSeparator = new System.Windows.Forms.ToolStripSeparator();
|
||||
@ -121,7 +127,6 @@
|
||||
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
|
||||
this.OpenFileDialog = new System.Windows.Forms.OpenFileDialog();
|
||||
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||
this.ToolsBinSearchMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MainMenu.SuspendLayout();
|
||||
this.MainToolbar.SuspendLayout();
|
||||
this.StatusBar.SuspendLayout();
|
||||
@ -395,6 +400,13 @@
|
||||
this.ToolsMenu.Size = new System.Drawing.Size(47, 20);
|
||||
this.ToolsMenu.Text = "Tools";
|
||||
//
|
||||
// ToolsBinSearchMenu
|
||||
//
|
||||
this.ToolsBinSearchMenu.Name = "ToolsBinSearchMenu";
|
||||
this.ToolsBinSearchMenu.Size = new System.Drawing.Size(161, 22);
|
||||
this.ToolsBinSearchMenu.Text = "Binary Search...";
|
||||
this.ToolsBinSearchMenu.Click += new System.EventHandler(this.ToolsBinSearchMenu_Click);
|
||||
//
|
||||
// ToolsRpfBrowserMenu
|
||||
//
|
||||
this.ToolsRpfBrowserMenu.Name = "ToolsRpfBrowserMenu";
|
||||
@ -424,6 +436,8 @@
|
||||
this.LocationTextBox,
|
||||
this.GoButton,
|
||||
this.RefreshButton,
|
||||
this.toolStripSeparator10,
|
||||
this.EditModeButton,
|
||||
this.toolStripSeparator1,
|
||||
this.SearchTextBox,
|
||||
this.SearchButton});
|
||||
@ -496,7 +510,7 @@
|
||||
// LocationTextBox
|
||||
//
|
||||
this.LocationTextBox.Name = "LocationTextBox";
|
||||
this.LocationTextBox.Size = new System.Drawing.Size(510, 25);
|
||||
this.LocationTextBox.Size = new System.Drawing.Size(423, 25);
|
||||
this.LocationTextBox.Enter += new System.EventHandler(this.LocationTextBox_Enter);
|
||||
this.LocationTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.LocationTextBox_KeyPress);
|
||||
//
|
||||
@ -522,6 +536,22 @@
|
||||
this.RefreshButton.Text = "Refresh All";
|
||||
this.RefreshButton.Click += new System.EventHandler(this.RefreshButton_Click);
|
||||
//
|
||||
// toolStripSeparator10
|
||||
//
|
||||
this.toolStripSeparator10.Name = "toolStripSeparator10";
|
||||
this.toolStripSeparator10.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// EditModeButton
|
||||
//
|
||||
this.EditModeButton.Enabled = false;
|
||||
this.EditModeButton.Image = ((System.Drawing.Image)(resources.GetObject("EditModeButton.Image")));
|
||||
this.EditModeButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.EditModeButton.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.EditModeButton.Name = "EditModeButton";
|
||||
this.EditModeButton.Size = new System.Drawing.Size(81, 22);
|
||||
this.EditModeButton.Text = "Edit mode";
|
||||
this.EditModeButton.Click += new System.EventHandler(this.EditModeButton_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
@ -676,6 +706,7 @@
|
||||
this.MainListView.UseCompatibleStateImageBehavior = false;
|
||||
this.MainListView.View = System.Windows.Forms.View.Details;
|
||||
this.MainListView.VirtualMode = true;
|
||||
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.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.MainListView_RetrieveVirtualItem);
|
||||
@ -720,6 +751,7 @@
|
||||
this.ListContextExtractUncompressedMenu,
|
||||
this.ListContextExtractAllMenu,
|
||||
this.toolStripSeparator5,
|
||||
this.ListContextNewMenu,
|
||||
this.ListContextImportXmlMenu,
|
||||
this.ListContextImportRawMenu,
|
||||
this.ListContextImportSeparator,
|
||||
@ -735,7 +767,7 @@
|
||||
this.ListContextEditSeparator,
|
||||
this.ListContextSelectAllMenu});
|
||||
this.ListContextMenu.Name = "MainContextMenu";
|
||||
this.ListContextMenu.Size = new System.Drawing.Size(208, 392);
|
||||
this.ListContextMenu.Size = new System.Drawing.Size(208, 414);
|
||||
//
|
||||
// ListContextViewMenu
|
||||
//
|
||||
@ -799,6 +831,29 @@
|
||||
this.toolStripSeparator5.Name = "toolStripSeparator5";
|
||||
this.toolStripSeparator5.Size = new System.Drawing.Size(204, 6);
|
||||
//
|
||||
// ListContextNewMenu
|
||||
//
|
||||
this.ListContextNewMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ListContextNewFolderMenu,
|
||||
this.ListContextNewRpfArchiveMenu});
|
||||
this.ListContextNewMenu.Name = "ListContextNewMenu";
|
||||
this.ListContextNewMenu.Size = new System.Drawing.Size(207, 22);
|
||||
this.ListContextNewMenu.Text = "New";
|
||||
//
|
||||
// ListContextNewFolderMenu
|
||||
//
|
||||
this.ListContextNewFolderMenu.Name = "ListContextNewFolderMenu";
|
||||
this.ListContextNewFolderMenu.Size = new System.Drawing.Size(146, 22);
|
||||
this.ListContextNewFolderMenu.Text = "Folder...";
|
||||
this.ListContextNewFolderMenu.Click += new System.EventHandler(this.ListContextNewFolderMenu_Click);
|
||||
//
|
||||
// ListContextNewRpfArchiveMenu
|
||||
//
|
||||
this.ListContextNewRpfArchiveMenu.Name = "ListContextNewRpfArchiveMenu";
|
||||
this.ListContextNewRpfArchiveMenu.Size = new System.Drawing.Size(146, 22);
|
||||
this.ListContextNewRpfArchiveMenu.Text = "RPF Archive...";
|
||||
this.ListContextNewRpfArchiveMenu.Click += new System.EventHandler(this.ListContextNewRpfArchiveMenu_Click);
|
||||
//
|
||||
// ListContextImportXmlMenu
|
||||
//
|
||||
this.ListContextImportXmlMenu.Image = ((System.Drawing.Image)(resources.GetObject("ListContextImportXmlMenu.Image")));
|
||||
@ -958,12 +1013,9 @@
|
||||
this.TreeContextCollapseAllMenu.Text = "Collapse All";
|
||||
this.TreeContextCollapseAllMenu.Click += new System.EventHandler(this.TreeContextCollapseAllMenu_Click);
|
||||
//
|
||||
// ToolsBinSearchMenu
|
||||
// OpenFileDialog
|
||||
//
|
||||
this.ToolsBinSearchMenu.Name = "ToolsBinSearchMenu";
|
||||
this.ToolsBinSearchMenu.Size = new System.Drawing.Size(161, 22);
|
||||
this.ToolsBinSearchMenu.Text = "Binary Search...";
|
||||
this.ToolsBinSearchMenu.Click += new System.EventHandler(this.ToolsBinSearchMenu_Click);
|
||||
this.OpenFileDialog.Multiselect = true;
|
||||
//
|
||||
// ExploreForm
|
||||
//
|
||||
@ -1090,5 +1142,10 @@
|
||||
private System.Windows.Forms.ToolStripSeparator ListContextOpenFileLocationSeparator;
|
||||
private System.Windows.Forms.ToolStripMenuItem ListContextExtractUncompressedMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem ToolsBinSearchMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem ListContextNewMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem ListContextNewFolderMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem ListContextNewRpfArchiveMenu;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator10;
|
||||
private System.Windows.Forms.ToolStripButton EditModeButton;
|
||||
}
|
||||
}
|
601
ExploreForm.cs
601
ExploreForm.cs
@ -418,6 +418,7 @@ namespace CodeWalker
|
||||
GoButton.Enabled = true;
|
||||
RefreshButton.Enabled = true;
|
||||
SearchButton.Enabled = true;
|
||||
EditModeButton.Enabled = true;
|
||||
}
|
||||
|
||||
public void GoUp(MainTreeFolder toFolder = null)
|
||||
@ -626,10 +627,7 @@ namespace CodeWalker
|
||||
var exists = nodes.TryGetValue(parentpath, out node);
|
||||
if (!exists)
|
||||
{
|
||||
node = new MainTreeFolder();
|
||||
node.Name = parentname;
|
||||
node.Path = parentpath;
|
||||
node.FullPath = replpath + parentpath;
|
||||
node = CreateRootDirTreeFolder(parentname, parentpath, replpath + parentpath);
|
||||
nodes[parentpath] = node;
|
||||
}
|
||||
if (parentnode == null)
|
||||
@ -656,12 +654,7 @@ namespace CodeWalker
|
||||
|
||||
rpf.ScanStructure(UpdateStatus, UpdateErrorLog);
|
||||
|
||||
node = new MainTreeFolder();
|
||||
node.RpfFile = rpf;
|
||||
node.RpfFolder = rpf.Root;
|
||||
node.Name = rpf.Name;
|
||||
node.Path = relpath;
|
||||
node.FullPath = filepath;
|
||||
node = CreateRpfTreeFolder(rpf, relpath, filepath);
|
||||
|
||||
RecurseMainTreeViewRPF(node, allRpfs);
|
||||
|
||||
@ -717,11 +710,7 @@ namespace CodeWalker
|
||||
{
|
||||
foreach (var dir in fld.Directories)
|
||||
{
|
||||
MainTreeFolder dtnf = new MainTreeFolder();
|
||||
dtnf.RpfFolder = dir;
|
||||
dtnf.Name = dir.Name;
|
||||
dtnf.Path = dir.Path;
|
||||
dtnf.FullPath = rootpath + dir.Path;
|
||||
var dtnf = CreateRpfDirTreeFolder(dir, dir.Path, rootpath + dir.Path);
|
||||
f.AddChild(dtnf);
|
||||
RecurseMainTreeViewRPF(dtnf, allRpfs);
|
||||
}
|
||||
@ -737,35 +726,22 @@ namespace CodeWalker
|
||||
{
|
||||
foreach (var child in rpf.Children)
|
||||
{
|
||||
MainTreeFolder ctnf = new MainTreeFolder();
|
||||
ctnf.RpfFile = child;
|
||||
ctnf.RpfFolder = child.Root;
|
||||
ctnf.Name = child.Name;
|
||||
ctnf.Path = child.Path;
|
||||
ctnf.FullPath = rootpath + child.Path;
|
||||
var ctnf = CreateRpfTreeFolder(child, child.Path, rootpath + child.Path);
|
||||
f.AddChildToHierarchy(ctnf);
|
||||
RecurseMainTreeViewRPF(ctnf, allRpfs);
|
||||
}
|
||||
}
|
||||
|
||||
JenkIndex.Ensure(rpf.Name);
|
||||
//JenkIndex.Ensure(rpf.Name);
|
||||
if (rpf.AllEntries != null)
|
||||
{
|
||||
foreach (RpfEntry entry in rpf.AllEntries)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entry.NameLower)) continue;
|
||||
JenkIndex.Ensure(entry.Name);
|
||||
JenkIndex.Ensure(entry.NameLower);
|
||||
entry.NameHash = JenkHash.GenHash(entry.NameLower);
|
||||
int ind = entry.Name.LastIndexOf('.');
|
||||
if (ind > 0)
|
||||
{
|
||||
var shortname = entry.Name.Substring(0, ind);
|
||||
var shortnamel = entry.NameLower.Substring(0, ind);
|
||||
JenkIndex.Ensure(shortname);
|
||||
var shortnamel = entry.GetShortNameLower();
|
||||
JenkIndex.Ensure(shortnamel);
|
||||
entry.ShortNameHash = JenkHash.GenHash(shortnamel);
|
||||
}
|
||||
entry.NameHash = JenkHash.GenHash(entry.NameLower);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -786,6 +762,7 @@ namespace CodeWalker
|
||||
ForwardButton.Enabled = false;
|
||||
RefreshButton.Enabled = false;
|
||||
SearchButton.Enabled = false;
|
||||
EditModeButton.Enabled = false;
|
||||
MainTreeView.Nodes.Clear();
|
||||
MainListView.VirtualListSize = 0; //also clear the list view...
|
||||
}
|
||||
@ -841,6 +818,8 @@ namespace CodeWalker
|
||||
tn.ToolTipText = f.Path;
|
||||
tn.Tag = f;
|
||||
|
||||
f.TreeNode = tn;
|
||||
|
||||
if (f.Children != null)
|
||||
{
|
||||
f.Children.Sort((n1, n2) => n1.Name.CompareTo(n2.Name));
|
||||
@ -882,6 +861,112 @@ namespace CodeWalker
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private void AddNewFolderTreeNode(MainTreeFolder f)
|
||||
{
|
||||
if (CurrentFolder == null) return;
|
||||
|
||||
RecurseAddMainTreeViewNodes(f, CurrentFolder.TreeNode);
|
||||
|
||||
CurrentFolder.AddChild(f);
|
||||
CurrentFolder.ListItems = null;
|
||||
|
||||
RefreshMainListView();
|
||||
}
|
||||
private MainTreeFolder CreateRpfTreeFolder(RpfFile rpf, string relpath, string fullpath)
|
||||
{
|
||||
var node = new MainTreeFolder();
|
||||
node.RpfFile = rpf;
|
||||
node.RpfFolder = rpf.Root;
|
||||
node.Name = rpf.Name;
|
||||
node.Path = relpath;
|
||||
node.FullPath = fullpath;
|
||||
return node;
|
||||
}
|
||||
private MainTreeFolder CreateRpfDirTreeFolder(RpfDirectoryEntry dir, string relpath, string fullpath)
|
||||
{
|
||||
var node = new MainTreeFolder();
|
||||
node.RpfFolder = dir;
|
||||
node.Name = dir.Name;
|
||||
node.Path = relpath;
|
||||
node.FullPath = fullpath;
|
||||
return node;
|
||||
}
|
||||
private MainTreeFolder CreateRootDirTreeFolder(string name, string path, string fullpath)
|
||||
{
|
||||
var node = new MainTreeFolder();
|
||||
node.Name = name;
|
||||
node.Path = path;
|
||||
node.FullPath = fullpath;
|
||||
return node;
|
||||
}
|
||||
private void RenameTreeFolder(MainTreeFolder f, string newname)
|
||||
{
|
||||
if (f.Parent == null) return;
|
||||
f.Name = newname;
|
||||
f.Path = f.Parent.Path + "\\" + newname.ToLowerInvariant();
|
||||
f.FullPath = f.Parent.FullPath + "\\" + newname;
|
||||
if (f.TreeNode != null)
|
||||
{
|
||||
f.TreeNode.Text = newname;
|
||||
}
|
||||
if (f.Children != null)
|
||||
{
|
||||
foreach (var item in f.Children)
|
||||
{
|
||||
RenameTreeFolder(item, item.Name);//just to make sure the all the paths are correct...
|
||||
}
|
||||
}
|
||||
if (f.ListItems != null)
|
||||
{
|
||||
foreach (var item in f.ListItems)
|
||||
{
|
||||
RenameListItem(item, item.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void RenameListItem(MainListItem i, string newname)
|
||||
{
|
||||
if (i.Parent == null) return;
|
||||
i.Name = newname;
|
||||
i.Path = i.Parent.Path + "\\" + newname.ToLowerInvariant();
|
||||
i.FullPath = i.Parent.FullPath + "\\" + newname;
|
||||
|
||||
if (i.Parent == CurrentFolder)
|
||||
{
|
||||
int idx = CurrentFiles.IndexOf(i);
|
||||
if (idx >= 0)
|
||||
{
|
||||
MainListView.RedrawItems(idx, idx, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void RemoveTreeFolder(MainTreeFolder f)
|
||||
{
|
||||
if (f.Parent == null) return;
|
||||
|
||||
f.Parent.Children?.Remove(f);
|
||||
|
||||
if (f.TreeNode != null)
|
||||
{
|
||||
f.TreeNode.Remove();
|
||||
}
|
||||
}
|
||||
private void RemoveListItem(MainListItem i)
|
||||
{
|
||||
if (i.Parent == null) return;
|
||||
|
||||
MainListView.VirtualListSize = 0;
|
||||
|
||||
i.Parent.ListItems?.Remove(i);
|
||||
|
||||
if (i.Parent == CurrentFolder)
|
||||
{
|
||||
CurrentFiles.Remove(i);//should really be the same list as above, but just in case...
|
||||
}
|
||||
|
||||
MainListView.VirtualListSize = CurrentFiles.Count;
|
||||
}
|
||||
|
||||
|
||||
private void RefreshMainListView()
|
||||
{
|
||||
@ -1430,12 +1515,11 @@ namespace CodeWalker
|
||||
bool isfile = false;
|
||||
bool isfolder = false;
|
||||
bool isfilesys = false;
|
||||
bool issearch = CurrentFolder?.IsSearchResults ?? false;
|
||||
bool canview = false;
|
||||
bool canexportxml = false;
|
||||
bool editmode = false;//todo: set this for edit mode
|
||||
bool canimport = editmode;
|
||||
bool canimport = EditMode && (CurrentFolder?.RpfFolder != null) && !issearch;
|
||||
bool canedit = false;
|
||||
bool issearch = CurrentFolder?.IsSearchResults ?? false;
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
@ -1445,7 +1529,7 @@ namespace CodeWalker
|
||||
canexportxml = CanExportXml(item);
|
||||
isitem = true;
|
||||
isfile = !isfolder;
|
||||
canedit = editmode && !canimport;
|
||||
canedit = EditMode && !issearch;
|
||||
}
|
||||
|
||||
|
||||
@ -1456,9 +1540,10 @@ namespace CodeWalker
|
||||
ListContextExtractRawMenu.Enabled = isfile;
|
||||
ListContextExtractUncompressedMenu.Enabled = isfile;
|
||||
|
||||
ListContextNewMenu.Visible = EditMode;
|
||||
ListContextImportRawMenu.Visible = canimport;
|
||||
ListContextImportXmlMenu.Visible = canimport;
|
||||
ListContextImportSeparator.Visible = canimport;
|
||||
ListContextImportSeparator.Visible = EditMode;
|
||||
|
||||
ListContextCopyMenu.Enabled = isfile;
|
||||
ListContextCopyPathMenu.Enabled = isitem;
|
||||
@ -1477,6 +1562,48 @@ namespace CodeWalker
|
||||
|
||||
|
||||
|
||||
|
||||
private void EnableEditMode(bool enable)
|
||||
{
|
||||
if (EditMode == enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (MessageBox.Show(this, "While in edit mode, all changes are automatically saved.\nDo you want to continue?", "Warning - Entering edit mode", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EditMode = enable;
|
||||
EditModeButton.Checked = enable;
|
||||
MainListView.LabelEdit = enable;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private bool IsFilenameOk(string name)
|
||||
{
|
||||
foreach (var ic in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
if (name.Contains(ic))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void ViewSelected()
|
||||
{
|
||||
for (int i = 0; i < MainListView.SelectedIndices.Count; i++)
|
||||
@ -1798,15 +1925,182 @@ namespace CodeWalker
|
||||
MessageBox.Show("Errors were encountered:\n" + errstr);
|
||||
}
|
||||
}
|
||||
private void NewFolder()
|
||||
{
|
||||
if (CurrentFolder == null) return;//shouldn't happen
|
||||
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||
|
||||
string fname = Prompt.ShowDialog(this, "Enter a name for the new folder:", "Create folder", "folder");
|
||||
if (string.IsNullOrEmpty(fname))
|
||||
{
|
||||
return;//no name was provided.
|
||||
}
|
||||
if (!IsFilenameOk(fname)) return; //new name contains invalid char(s). don't do anything
|
||||
|
||||
|
||||
string relpath = (CurrentFolder.Path ?? "") + "\\" + fname;
|
||||
var rootpath = GetRootPath();
|
||||
string fullpath = rootpath + relpath;
|
||||
|
||||
RpfDirectoryEntry newdir = null;
|
||||
MainTreeFolder node = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (CurrentFolder.RpfFolder != null)
|
||||
{
|
||||
//create new directory entry in the RPF.
|
||||
|
||||
newdir = RpfFile.CreateDirectory(CurrentFolder.RpfFolder, fname);
|
||||
|
||||
node = CreateRpfDirTreeFolder(newdir, relpath, fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
//create a folder in the filesystem.
|
||||
if (Directory.Exists(fullpath))
|
||||
{
|
||||
throw new Exception("Folder " + fullpath + " already exists!");
|
||||
}
|
||||
Directory.CreateDirectory(fullpath);
|
||||
|
||||
node = CreateRootDirTreeFolder(fname, relpath, fullpath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error creating new folder: " + ex.Message, "Unable to create new folder");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
AddNewFolderTreeNode(node);
|
||||
}
|
||||
|
||||
}
|
||||
private void NewRpfArchive()
|
||||
{
|
||||
if (CurrentFolder == null) return;//shouldn't happen
|
||||
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||
|
||||
string fname = Prompt.ShowDialog(this, "Enter a name for the new archive:", "Create RPF7 archive", "new");
|
||||
if (string.IsNullOrEmpty(fname))
|
||||
{
|
||||
return;//no name was provided.
|
||||
}
|
||||
if (!IsFilenameOk(fname)) return; //new name contains invalid char(s). don't do anything
|
||||
|
||||
if (!fname.ToLowerInvariant().EndsWith(".rpf"))
|
||||
{
|
||||
fname = fname + ".rpf";//make sure it ends with .rpf
|
||||
}
|
||||
string relpath = (CurrentFolder.Path ?? "") + "\\" + fname.ToLowerInvariant();
|
||||
|
||||
|
||||
RpfEncryption encryption = RpfEncryption.OPEN;//TODO: select encryption mode
|
||||
|
||||
RpfFile newrpf = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (CurrentFolder.RpfFolder != null)
|
||||
{
|
||||
//adding a new RPF as a child of another
|
||||
newrpf = RpfFile.CreateNew(CurrentFolder.RpfFolder, fname, encryption);
|
||||
}
|
||||
else
|
||||
{
|
||||
//adding a new RPF in the filesystem
|
||||
newrpf = RpfFile.CreateNew(Settings.Default.GTAFolder, relpath, encryption);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error creating archive: " + ex.Message, "Unable to create new archive");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (newrpf != null)
|
||||
{
|
||||
var node = CreateRpfTreeFolder(newrpf, newrpf.Path, GetRootPath() + newrpf.Path);
|
||||
RecurseMainTreeViewRPF(node, AllRpfs);
|
||||
AddNewFolderTreeNode(node);
|
||||
}
|
||||
|
||||
}
|
||||
private void ImportXml()
|
||||
{
|
||||
if (!EditMode) return;
|
||||
MessageBox.Show("Edit mode functions not yet implemented...");
|
||||
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||
MessageBox.Show("Import XML TODO...");
|
||||
}
|
||||
private void ImportRaw()
|
||||
{
|
||||
if (!EditMode) return;
|
||||
MessageBox.Show("Edit mode functions not yet implemented...");
|
||||
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 (OpenFileDialog.ShowDialog(this) != DialogResult.OK)
|
||||
{
|
||||
return;//canceled
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var fpaths = OpenFileDialog.FileNames;
|
||||
foreach (var fpath in fpaths)
|
||||
{
|
||||
if (!File.Exists(fpath))
|
||||
{
|
||||
continue;//this shouldn't happen...
|
||||
}
|
||||
|
||||
var fi = new FileInfo(fpath);
|
||||
var fname = fi.Name;
|
||||
var fnamel = fname.ToLowerInvariant();
|
||||
|
||||
if (fi.Length > 0x3FFFFFFF)
|
||||
{
|
||||
MessageBox.Show("File " + fname + " is too big! Max 1GB supported.", "Unable to import file");
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte[] data = File.ReadAllBytes(fpath);
|
||||
|
||||
|
||||
RpfFile.CreateFile(parentrpffldr, fname, data);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "Unable to import file");
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentFolder.ListItems = null;
|
||||
RefreshMainListView();
|
||||
}
|
||||
private void CopySelected()
|
||||
{
|
||||
@ -1863,19 +2157,156 @@ namespace CodeWalker
|
||||
private void RenameSelected()
|
||||
{
|
||||
if (!EditMode) return;
|
||||
if (MainListView.SelectedItems.Count != 1) return;
|
||||
MessageBox.Show("Edit mode functions not yet implemented...");
|
||||
if (MainListView.SelectedIndices.Count != 1) return;
|
||||
var idx = MainListView.SelectedIndices[0];
|
||||
if ((CurrentFiles != null) && (CurrentFiles.Count > idx))
|
||||
{
|
||||
var item = CurrentFiles[idx];
|
||||
string newname = Prompt.ShowDialog(this, "Enter the new name for this item:", "Rename item", item.Name);
|
||||
if (!string.IsNullOrEmpty(newname))
|
||||
{
|
||||
RenameItem(item, newname);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void RenameItem(MainListItem item, string newname)
|
||||
{
|
||||
if (!EditMode) return;
|
||||
if (item.Name == newname) return;
|
||||
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||
if (!IsFilenameOk(newname)) return; //new name contains invalid char(s). don't do anything
|
||||
|
||||
|
||||
RpfFile file = item.Folder?.RpfFile;
|
||||
RpfEntry entry = item.GetRpfEntry();
|
||||
|
||||
try
|
||||
{
|
||||
if (file != null)
|
||||
{
|
||||
//updates all items in the RPF with the new path - no actual file changes made here
|
||||
RpfFile.RenameArchive(file, newname);
|
||||
}
|
||||
if (entry != null)
|
||||
{
|
||||
//renaming an entry in an RPF
|
||||
RpfFile.RenameEntry(entry, newname);
|
||||
}
|
||||
else
|
||||
{
|
||||
//renaming a filesystem item...
|
||||
var dirinfo = new DirectoryInfo(item.FullPath);
|
||||
var newpath = Path.Combine(dirinfo.Parent.FullName, newname);
|
||||
if (item.FullPath.ToLowerInvariant() == newpath.ToLowerInvariant())
|
||||
{
|
||||
return;//filesystem tends to be case-insensitive... paths are the same
|
||||
}
|
||||
if ((item.Folder != null) && (item.Folder.RpfFile == null))
|
||||
{
|
||||
//renaming a filesystem folder...
|
||||
Directory.Move(item.FullPath, newpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
//renaming a filesystem file...
|
||||
File.Move(item.FullPath, newpath);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Folder != null)
|
||||
{
|
||||
RenameTreeFolder(item.Folder, newname);
|
||||
}
|
||||
|
||||
RenameListItem(item, newname);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error renaming " + item.Path + ": " + ex.Message, "Unable to rename item");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
private void ReplaceSelected()
|
||||
{
|
||||
if (!EditMode) return;
|
||||
if (MainListView.SelectedItems.Count != 1) return;
|
||||
MessageBox.Show("Edit mode functions not yet implemented...");
|
||||
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||
if (MainListView.SelectedIndices.Count != 1) return;
|
||||
MessageBox.Show("ReplaceSelected TODO...");
|
||||
//delete the selected items, and replace with... choose
|
||||
}
|
||||
private void DeleteSelected()
|
||||
{
|
||||
if (!EditMode) return;
|
||||
MessageBox.Show("Edit mode functions not yet implemented...");
|
||||
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||
if (MainListView.SelectedIndices.Count <= 0) return;
|
||||
//if (MainListView.SelectedIndices.Count == 1) //is confirmation always really necessary?
|
||||
//{
|
||||
// var item = CurrentFiles[MainListView.SelectedIndices[0]];
|
||||
// if (MessageBox.Show("Are you sure you want to permantly delete " + item.Name + "?\nThis cannot be undone.", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// if (MessageBox.Show("Are you sure you want to permantly delete " + MainListView.SelectedIndices.Count.ToString() + " items?\nThis cannot be undone.", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
var delitems = new List<MainListItem>();
|
||||
foreach (int idx in MainListView.SelectedIndices)
|
||||
{
|
||||
if ((idx < 0) || (idx >= CurrentFiles.Count)) return;
|
||||
var f = CurrentFiles[idx];//this could change when deleting.. so need to use the temp list
|
||||
delitems.Add(f);
|
||||
}
|
||||
foreach (var f in delitems)
|
||||
{
|
||||
DeleteItem(f);
|
||||
}
|
||||
}
|
||||
private void DeleteItem(MainListItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parent = item.Parent;
|
||||
if (parent.RpfFolder != null)
|
||||
{
|
||||
//delete an item in an RPF.
|
||||
RpfEntry entry = item.GetRpfEntry();
|
||||
|
||||
RpfFile.DeleteEntry(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
//delete an item in the filesystem.
|
||||
if ((item.Folder != null) && (item.Folder.RpfFile == null))
|
||||
{
|
||||
Directory.Delete(item.FullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Delete(item.FullPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (item.Folder != null)
|
||||
{
|
||||
RemoveTreeFolder(item.Folder);
|
||||
}
|
||||
|
||||
RemoveListItem(item);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error deleting " + item.Path + ": " + ex.Message, "Unable to delete " + item.Name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
private void SelectAll()
|
||||
{
|
||||
@ -2116,6 +2547,14 @@ namespace CodeWalker
|
||||
}
|
||||
}
|
||||
|
||||
private void MainListView_AfterLabelEdit(object sender, LabelEditEventArgs e)
|
||||
{
|
||||
if ((CurrentFiles != null) && (CurrentFiles.Count > e.Item) && (!string.IsNullOrEmpty(e.Label)))
|
||||
{
|
||||
RenameItem(CurrentFiles[e.Item], e.Label);
|
||||
}
|
||||
}
|
||||
|
||||
private void BackButton_ButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
GoBack();
|
||||
@ -2183,6 +2622,11 @@ namespace CodeWalker
|
||||
});
|
||||
}
|
||||
|
||||
private void EditModeButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
EnableEditMode(!EditMode);
|
||||
}
|
||||
|
||||
private void SearchTextBox_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == 13)
|
||||
@ -2298,6 +2742,16 @@ namespace CodeWalker
|
||||
ExtractAll();
|
||||
}
|
||||
|
||||
private void ListContextNewFolderMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
NewFolder();
|
||||
}
|
||||
|
||||
private void ListContextNewRpfArchiveMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
NewRpfArchive();
|
||||
}
|
||||
|
||||
private void ListContextImportXmlMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
ImportXml();
|
||||
@ -2474,6 +2928,7 @@ namespace CodeWalker
|
||||
public MainTreeFolder Parent { get; set; }
|
||||
public List<MainTreeFolder> Children { get; set; }
|
||||
public List<MainListItem> ListItems { get; set; }
|
||||
public TreeNode TreeNode { get; set; }
|
||||
public bool IsSearchResults { get; set; }
|
||||
public string SearchTerm { get; set; }
|
||||
|
||||
@ -2768,6 +3223,27 @@ namespace CodeWalker
|
||||
//return i1.Name.CompareTo(i2.Name);
|
||||
}
|
||||
|
||||
public RpfEntry GetRpfEntry()
|
||||
{
|
||||
RpfFile file = Folder?.RpfFile;
|
||||
RpfDirectoryEntry fldr = Folder?.RpfFolder;
|
||||
RpfEntry entry = File;
|
||||
if (entry == null)
|
||||
{
|
||||
if (file != null)
|
||||
{
|
||||
//for an RPF file, get its entry in the parent (if any).
|
||||
entry = file.ParentFileEntry;
|
||||
}
|
||||
else if (fldr != null)
|
||||
{
|
||||
//RPF folders are referenced in the item.Folder
|
||||
entry = fldr;
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -2817,4 +3293,41 @@ namespace CodeWalker
|
||||
ViewCacheDat = 18,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class Prompt
|
||||
{
|
||||
public static string ShowDialog(IWin32Window owner, string text, string caption, string defaultvalue = "")
|
||||
{
|
||||
Form prompt = new Form()
|
||||
{
|
||||
Width = 450,
|
||||
Height = 150,
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog,
|
||||
Text = caption,
|
||||
StartPosition = FormStartPosition.CenterParent,
|
||||
MaximizeBox = false,
|
||||
MinimizeBox = false
|
||||
};
|
||||
Label textLabel = new Label() { Left = 30, Top = 20, Width = 370, Height = 20, Text = text, };
|
||||
TextBox textBox = new TextBox() { Left = 30, Top = 40, Width = 370, Text = defaultvalue };
|
||||
Button cancel = new Button() { Text = "Cancel", Left = 230, Width = 80, Top = 70, DialogResult = DialogResult.Cancel };
|
||||
Button confirmation = new Button() { Text = "Ok", Left = 320, Width = 80, Top = 70, DialogResult = DialogResult.OK };
|
||||
cancel.Click += (sender, e) => { prompt.Close(); };
|
||||
confirmation.Click += (sender, e) => { prompt.Close(); };
|
||||
prompt.Controls.Add(textBox);
|
||||
prompt.Controls.Add(confirmation);
|
||||
prompt.Controls.Add(cancel);
|
||||
prompt.Controls.Add(textLabel);
|
||||
prompt.AcceptButton = confirmation;
|
||||
|
||||
return prompt.ShowDialog(owner) == DialogResult.OK ? textBox.Text : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,6 +258,19 @@
|
||||
GvZP7/3NqMHOyEACQlVVHxGjBiOpbdu1KIokGRDjZCqQj/3WzsPozi3L8oNTCXEyAqDv+93PykyM7hyb
|
||||
OEgy37QlAVUSCxs9tKCADeqLDGjzT4Gu676IErtUgaDbuTwDCUhYccAhyS2wicsjWZXIJ9R1vYsbPdjm
|
||||
ePJI4uQjAWAz8UYNxvNEhJNVrq7ziMzzN2pq/DDMhNNPcE6+bs69AUIIBqGH+5QgAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="EditModeButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGKSURBVDhPjZM7T8JQFMfP4GpiGFhcGBwddPBVkBK0kKhR
|
||||
J8UoD4OoRGTxMRs3EyYHE2N8EF0wJiwuBhUTwecAH8DvwODe4z3tQSi3GP/JSZt7z+93e9tbsEswGPRp
|
||||
mlYUV6Sie1F9PN0+otkVCATOCRqYXUdnLIvlEx/uJMYNEc+5uL0RXq1CTd6pEHZHjxFSHwgb76g/eUS5
|
||||
8e5QxcicZoiolxjGjZWxZ/EAHSvXCJsCZBiSJHCjXlTMehzB6oUHL/dVQ8S4KYD0pwRD8s0C6w/DZt0P
|
||||
2QhsYFhjQQusFwZlgSOek2BYfbWFq2eKLHBGsxIMCSFoganKR25JkM9sj0kvjECIvyAslxFioqIlhEgJ
|
||||
e2d2SZBn3BDEyPiVG5X23Ap3LtwYqxPDuBkxUEmGNWnPzTCEn1GZjBBcYawROqpiopbZ8v/CtN9mmB+9
|
||||
1vZY1yV7KT9+37JAwB1LBeyfTv8N11OX0LGtniroCF2hd2L+f3A9qqp2iWbL30hjPP3/CJi+jvVtWwLw
|
||||
A4Rmgl76+inbAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="SearchGlobalButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
@ -300,7 +313,7 @@
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADo
|
||||
HwAAAk1TRnQBSQFMAgEBGAEAAaABAAGgAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
HwAAAk1TRnQBSQFMAgEBGAEAAdABAAHQAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
AwABQAMAAXADAAEBAQABCAYAARwYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
|
||||
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
|
||||
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
|
||||
|
@ -21,7 +21,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
RpfFileEntry = entry;
|
||||
Type = type;
|
||||
MemoryUsage = (entry != null) ? entry.FileSize : 0;
|
||||
MemoryUsage = (entry != null) ? entry.GetFileSize() : 0;
|
||||
if (entry is RpfResourceFileEntry)
|
||||
{
|
||||
var resent = entry as RpfResourceFileEntry;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,6 +39,10 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
return DecryptAESData(data, GTA5Keys.PC_AES_KEY);
|
||||
}
|
||||
public static byte[] EncryptAES(byte[] data)
|
||||
{
|
||||
return EncryptAESData(data, GTA5Keys.PC_AES_KEY);
|
||||
}
|
||||
|
||||
public static byte[] DecryptAESData(byte[] data, byte[] key, int rounds = 1)
|
||||
{
|
||||
@ -247,5 +251,179 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static byte[] EncryptNG(byte[] data, string name, uint length)
|
||||
{
|
||||
byte[] key = GetNGKey(name, length);
|
||||
return EncryptNG(data, key);
|
||||
}
|
||||
|
||||
public static byte[] EncryptNG(byte[] data, byte[] key)
|
||||
{
|
||||
if ((GTA5Keys.PC_NG_ENCRYPT_TABLES == null) || (GTA5Keys.PC_NG_ENCRYPT_LUTs == null))
|
||||
{
|
||||
throw new Exception("Unable to encrypt - tables not loaded.");
|
||||
}
|
||||
|
||||
var encryptedData = new byte[data.Length];
|
||||
|
||||
var keyuints = new uint[key.Length / 4];
|
||||
Buffer.BlockCopy(key, 0, keyuints, 0, key.Length);
|
||||
|
||||
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
|
||||
{
|
||||
byte[] decryptedBlock = new byte[16];
|
||||
Array.Copy(data, 16 * blockIndex, decryptedBlock, 0, 16);
|
||||
byte[] encryptedBlock = EncryptBlock(decryptedBlock, keyuints);
|
||||
Array.Copy(encryptedBlock, 0, encryptedData, 16 * blockIndex, 16);
|
||||
}
|
||||
|
||||
if (data.Length % 16 != 0)
|
||||
{
|
||||
var left = data.Length % 16;
|
||||
Buffer.BlockCopy(data, data.Length - left, encryptedData, data.Length - left, left);
|
||||
}
|
||||
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
public static byte[] EncryptBlock(byte[] data, uint[] key)
|
||||
{
|
||||
var buffer = data;
|
||||
|
||||
// prepare key...
|
||||
var subKeys = new uint[17][];
|
||||
for (int i = 0; i < 17; i++)
|
||||
{
|
||||
subKeys[i] = new uint[4];
|
||||
subKeys[i][0] = key[4 * i + 0];
|
||||
subKeys[i][1] = key[4 * i + 1];
|
||||
subKeys[i][2] = key[4 * i + 2];
|
||||
subKeys[i][3] = key[4 * i + 3];
|
||||
}
|
||||
|
||||
buffer = EncryptRoundA(buffer, subKeys[16], GTA5Keys.PC_NG_ENCRYPT_TABLES[16]);
|
||||
for (int k = 15; k >= 2; k--)
|
||||
buffer = EncryptRoundB_LUT(buffer, subKeys[k], GTA5Keys.PC_NG_ENCRYPT_LUTs[k]);
|
||||
buffer = EncryptRoundA(buffer, subKeys[1], GTA5Keys.PC_NG_ENCRYPT_TABLES[1]);
|
||||
buffer = EncryptRoundA(buffer, subKeys[0], GTA5Keys.PC_NG_ENCRYPT_TABLES[0]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] EncryptRoundA(byte[] data, uint[] key, uint[][] table)
|
||||
{
|
||||
// apply xor to data first...
|
||||
var xorbuf = new byte[16];
|
||||
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
|
||||
|
||||
var x1 =
|
||||
table[0][data[0] ^ xorbuf[0]] ^
|
||||
table[1][data[1] ^ xorbuf[1]] ^
|
||||
table[2][data[2] ^ xorbuf[2]] ^
|
||||
table[3][data[3] ^ xorbuf[3]];
|
||||
var x2 =
|
||||
table[4][data[4] ^ xorbuf[4]] ^
|
||||
table[5][data[5] ^ xorbuf[5]] ^
|
||||
table[6][data[6] ^ xorbuf[6]] ^
|
||||
table[7][data[7] ^ xorbuf[7]];
|
||||
var x3 =
|
||||
table[8][data[8] ^ xorbuf[8]] ^
|
||||
table[9][data[9] ^ xorbuf[9]] ^
|
||||
table[10][data[10] ^ xorbuf[10]] ^
|
||||
table[11][data[11] ^ xorbuf[11]];
|
||||
var x4 =
|
||||
table[12][data[12] ^ xorbuf[12]] ^
|
||||
table[13][data[13] ^ xorbuf[13]] ^
|
||||
table[14][data[14] ^ xorbuf[14]] ^
|
||||
table[15][data[15] ^ xorbuf[15]];
|
||||
|
||||
var buf = new byte[16];
|
||||
Array.Copy(BitConverter.GetBytes(x1), 0, buf, 0, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x2), 0, buf, 4, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x3), 0, buf, 8, 4);
|
||||
Array.Copy(BitConverter.GetBytes(x4), 0, buf, 12, 4);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static byte[] EncryptRoundA_LUT(byte[] dataOld, uint[] key, GTA5NGLUT[] lut)
|
||||
{
|
||||
var data = (byte[])dataOld.Clone();
|
||||
|
||||
// apply xor to data first...
|
||||
var xorbuf = new byte[16];
|
||||
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
data[y] ^= xorbuf[y];
|
||||
}
|
||||
|
||||
return new byte[] {
|
||||
lut[0].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[1].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[2].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[3].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[4].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[5].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[6].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[7].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[8].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[9].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[10].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[11].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[12].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[13].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[14].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[15].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0))
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] EncryptRoundB_LUT(byte[] dataOld, uint[] key, GTA5NGLUT[] lut)
|
||||
{
|
||||
var data = (byte[])dataOld.Clone();
|
||||
|
||||
// apply xor to data first...
|
||||
var xorbuf = new byte[16];
|
||||
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
data[y] ^= xorbuf[y];
|
||||
}
|
||||
|
||||
return new byte[] {
|
||||
lut[0].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[1].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[2].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[3].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[4].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[5].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[6].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[7].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[8].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
|
||||
lut[9].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[10].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[11].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[12].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
|
||||
lut[13].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
|
||||
lut[14].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
|
||||
lut[15].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0))};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user