mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 00:43:00 +08:00
RPF Explorer archive defragmenting tool
This commit is contained in:
parent
02a6b0f33c
commit
8d30a1ff77
22
ExploreForm.Designer.cs
generated
22
ExploreForm.Designer.cs
generated
@ -133,6 +133,8 @@
|
|||||||
this.EditModeModsWarningPanel = new System.Windows.Forms.Panel();
|
this.EditModeModsWarningPanel = new System.Windows.Forms.Panel();
|
||||||
this.pictureBox2 = new System.Windows.Forms.PictureBox();
|
this.pictureBox2 = new System.Windows.Forms.PictureBox();
|
||||||
this.label2 = new System.Windows.Forms.Label();
|
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.MainMenu.SuspendLayout();
|
||||||
this.MainToolbar.SuspendLayout();
|
this.MainToolbar.SuspendLayout();
|
||||||
this.StatusBar.SuspendLayout();
|
this.StatusBar.SuspendLayout();
|
||||||
@ -173,7 +175,7 @@
|
|||||||
//
|
//
|
||||||
this.FileExitMenu.Name = "FileExitMenu";
|
this.FileExitMenu.Name = "FileExitMenu";
|
||||||
this.FileExitMenu.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4)));
|
this.FileExitMenu.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4)));
|
||||||
this.FileExitMenu.Size = new System.Drawing.Size(134, 22);
|
this.FileExitMenu.Size = new System.Drawing.Size(152, 22);
|
||||||
this.FileExitMenu.Text = "Exit";
|
this.FileExitMenu.Text = "Exit";
|
||||||
this.FileExitMenu.Click += new System.EventHandler(this.FileExitMenu_Click);
|
this.FileExitMenu.Click += new System.EventHandler(this.FileExitMenu_Click);
|
||||||
//
|
//
|
||||||
@ -777,9 +779,11 @@
|
|||||||
this.ListContextReplaceMenu,
|
this.ListContextReplaceMenu,
|
||||||
this.ListContextDeleteMenu,
|
this.ListContextDeleteMenu,
|
||||||
this.ListContextEditSeparator,
|
this.ListContextEditSeparator,
|
||||||
|
this.ListContextDefragmentMenu,
|
||||||
|
this.ListContextDefragmentSeparator,
|
||||||
this.ListContextSelectAllMenu});
|
this.ListContextSelectAllMenu});
|
||||||
this.ListContextMenu.Name = "MainContextMenu";
|
this.ListContextMenu.Name = "MainContextMenu";
|
||||||
this.ListContextMenu.Size = new System.Drawing.Size(208, 414);
|
this.ListContextMenu.Size = new System.Drawing.Size(208, 464);
|
||||||
//
|
//
|
||||||
// ListContextViewMenu
|
// ListContextViewMenu
|
||||||
//
|
//
|
||||||
@ -1095,6 +1099,18 @@
|
|||||||
this.label2.TabIndex = 0;
|
this.label2.TabIndex = 0;
|
||||||
this.label2.Text = "You are editing files in the mods folder";
|
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
|
// ExploreForm
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
@ -1237,5 +1253,7 @@
|
|||||||
private System.Windows.Forms.Panel EditModeModsWarningPanel;
|
private System.Windows.Forms.Panel EditModeModsWarningPanel;
|
||||||
private System.Windows.Forms.PictureBox pictureBox2;
|
private System.Windows.Forms.PictureBox pictureBox2;
|
||||||
private System.Windows.Forms.Label label2;
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.ToolStripMenuItem ListContextDefragmentMenu;
|
||||||
|
private System.Windows.Forms.ToolStripSeparator ListContextDefragmentSeparator;
|
||||||
}
|
}
|
||||||
}
|
}
|
138
ExploreForm.cs
138
ExploreForm.cs
@ -1536,6 +1536,7 @@ namespace CodeWalker
|
|||||||
bool canimport = EditMode && (CurrentFolder?.RpfFolder != null) && !issearch;
|
bool canimport = EditMode && (CurrentFolder?.RpfFolder != null) && !issearch;
|
||||||
bool cancreate = EditMode && !issearch;
|
bool cancreate = EditMode && !issearch;
|
||||||
bool canedit = false;
|
bool canedit = false;
|
||||||
|
bool candefrag = false;
|
||||||
|
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
@ -1549,6 +1550,7 @@ namespace CodeWalker
|
|||||||
canexportxml = CanExportXml(item);
|
canexportxml = CanExportXml(item);
|
||||||
canedit = EditMode && !issearch;
|
canedit = EditMode && !issearch;
|
||||||
canextract = isfile || (isarchive && !isfilesys);
|
canextract = isfile || (isarchive && !isfilesys);
|
||||||
|
candefrag = isarchive && canedit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1575,6 +1577,9 @@ namespace CodeWalker
|
|||||||
ListContextDeleteMenu.Visible = canedit;
|
ListContextDeleteMenu.Visible = canedit;
|
||||||
ListContextEditSeparator.Visible = canedit;
|
ListContextEditSeparator.Visible = canedit;
|
||||||
|
|
||||||
|
ListContextDefragmentMenu.Visible = candefrag;
|
||||||
|
ListContextDefragmentSeparator.Visible = candefrag;
|
||||||
|
|
||||||
ListContextMenu.Show(Cursor.Position);
|
ListContextMenu.Show(Cursor.Position);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1606,7 +1611,9 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void EnsureEditModeWarning()
|
private void EnsureEditModeWarning()
|
||||||
{
|
{
|
||||||
bool show = EditMode && !CurrentFolder.Path.ToLowerInvariant().StartsWith("mods");
|
bool mods = CurrentFolder.Path.ToLowerInvariant().StartsWith("mods");
|
||||||
|
bool srch = CurrentFolder?.IsSearchResults ?? false;
|
||||||
|
bool show = EditMode && !mods && !srch;
|
||||||
int gap = 3;
|
int gap = 3;
|
||||||
int bot = MainListView.Bottom;
|
int bot = MainListView.Bottom;
|
||||||
|
|
||||||
@ -1643,6 +1650,10 @@ namespace CodeWalker
|
|||||||
|
|
||||||
var rpf = CurrentFolder.RpfFolder.File;
|
var rpf = CurrentFolder.RpfFolder.File;
|
||||||
|
|
||||||
|
return EnsureRpfValidEncryption(rpf);
|
||||||
|
}
|
||||||
|
private bool EnsureRpfValidEncryption(RpfFile rpf)
|
||||||
|
{
|
||||||
if (rpf == null) return false;
|
if (rpf == null) return false;
|
||||||
|
|
||||||
bool needsupd = false;
|
bool needsupd = false;
|
||||||
@ -1679,7 +1690,6 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void ViewSelected()
|
private void ViewSelected()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MainListView.SelectedIndices.Count; i++)
|
for (int i = 0; i < MainListView.SelectedIndices.Count; i++)
|
||||||
@ -2360,6 +2370,7 @@ namespace CodeWalker
|
|||||||
private void RenameSelected()
|
private void RenameSelected()
|
||||||
{
|
{
|
||||||
if (!EditMode) return;
|
if (!EditMode) return;
|
||||||
|
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||||
if (MainListView.SelectedIndices.Count != 1) return;
|
if (MainListView.SelectedIndices.Count != 1) return;
|
||||||
var idx = MainListView.SelectedIndices[0];
|
var idx = MainListView.SelectedIndices[0];
|
||||||
if ((CurrentFiles != null) && (CurrentFiles.Count > idx))
|
if ((CurrentFiles != null) && (CurrentFiles.Count > idx))
|
||||||
@ -2480,6 +2491,15 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (item.Folder?.RpfFile != null)
|
||||||
|
{
|
||||||
|
//confirm deletion of RPF archives, just to be friendly.
|
||||||
|
if (MessageBox.Show("Are you sure you want to delete this archive?\n" + item.Path, "Confirm delete archive", MessageBoxButtons.YesNo) != DialogResult.Yes)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var parent = item.Parent;
|
var parent = item.Parent;
|
||||||
if (parent.RpfFolder != null)
|
if (parent.RpfFolder != null)
|
||||||
{
|
{
|
||||||
@ -2518,6 +2538,86 @@ namespace CodeWalker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void DefragmentSelected()
|
||||||
|
{
|
||||||
|
if (!EditMode) return;
|
||||||
|
if (CurrentFolder?.IsSearchResults ?? false) return;
|
||||||
|
if (MainListView.SelectedIndices.Count != 1)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Can only defragment one item at a time. Please have only one item selected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var idx = MainListView.SelectedIndices[0];
|
||||||
|
if ((CurrentFiles == null) || (CurrentFiles.Count <= idx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = CurrentFiles[idx];
|
||||||
|
var rpf = item.Folder?.RpfFile;
|
||||||
|
if (rpf == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Can only defragment RPF archives!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Form form = new Form() {
|
||||||
|
Width = 450,
|
||||||
|
Height = 250,
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedDialog,
|
||||||
|
Text = "Defragment RPF Archive - CodeWalker by dexyfex",
|
||||||
|
StartPosition = FormStartPosition.CenterParent,
|
||||||
|
MaximizeBox = false,
|
||||||
|
MinimizeBox = false
|
||||||
|
};
|
||||||
|
var addCtrl = new Func<Control, Control>(c => { form.Controls.Add(c); return c; });
|
||||||
|
var addLabel = new Func<int, string, Control>((y, t) => {
|
||||||
|
return addCtrl(new Label() { Left = 30, Top = y, Width = 370, Height = 20, Text = t });
|
||||||
|
});
|
||||||
|
var rpfNameLabel = addLabel(20, "Archive: " + rpf.Path);
|
||||||
|
var curSizeLabel = addLabel(40, string.Empty);
|
||||||
|
var newSizeLabel = addLabel(60, string.Empty);
|
||||||
|
var redSizeLabel = addLabel(80, string.Empty);
|
||||||
|
var statusLabel = addLabel(110, string.Empty);
|
||||||
|
var progressBar = addCtrl(new ProgressBar() { Left = 30, Top = 130, Width = 370, Height = 20, Minimum = 0, Maximum = 1000, MarqueeAnimationSpeed = 50 }) as ProgressBar;
|
||||||
|
var beginButton = addCtrl(new Button() { Text = "Begin Defragment", Left = 30, Top = 170, Width = 120 }) as Button;
|
||||||
|
var closeButton = addCtrl(new Button() { Text = "Close", Left = 320, Top = 170, Width = 80 }) as Button;
|
||||||
|
var inProgress = false;
|
||||||
|
var updateProgress = new Action<string, float>((s, p) => { form.Invoke(new Action(() => {
|
||||||
|
statusLabel.Text = s;
|
||||||
|
progressBar.Value = Math.Max(0, Math.Min((int)(p * 1000), 1000));//p in range 0..1
|
||||||
|
}));});
|
||||||
|
var updateSizeLabels = new Action<bool>((init) => {
|
||||||
|
var curSize = rpf.FileSize;
|
||||||
|
var newSize = rpf.GetDefragmentedFileSize();
|
||||||
|
var redSize = curSize - newSize;
|
||||||
|
curSizeLabel.Text = "Archive current size: " + TextUtil.GetBytesReadable(curSize);
|
||||||
|
newSizeLabel.Text = "Defragmented size: " + TextUtil.GetBytesReadable(newSize);
|
||||||
|
redSizeLabel.Text = "Size reduction: " + TextUtil.GetBytesReadable(redSize);
|
||||||
|
if (init) statusLabel.Text = (redSize <= 0) ? "Defragmentation not required." : "Ready to defragment.";
|
||||||
|
});
|
||||||
|
var enableUi = new Action<bool>(enable => { form.Invoke(new Action(() => {
|
||||||
|
beginButton.Enabled = enable;
|
||||||
|
closeButton.Enabled = enable;
|
||||||
|
}));});
|
||||||
|
var defragment = new Action(() => { Task.Run(() => {
|
||||||
|
if (inProgress) return;
|
||||||
|
if (!EnsureRpfValidEncryption(rpf)) return;
|
||||||
|
inProgress = true;
|
||||||
|
enableUi(false);
|
||||||
|
RpfFile.Defragment(rpf, updateProgress);
|
||||||
|
updateProgress("Defragment complete.", 1.0f);
|
||||||
|
enableUi(true);
|
||||||
|
form.Invoke(new Action(() => { updateSizeLabels(false); }));
|
||||||
|
inProgress = false;
|
||||||
|
});});
|
||||||
|
updateSizeLabels(true);
|
||||||
|
beginButton.Click += (sender, e) => { defragment(); };
|
||||||
|
closeButton.Click += (sender, e) => { form.Close(); };
|
||||||
|
form.FormClosing += (s, e) => { e.Cancel = inProgress; };
|
||||||
|
form.ShowDialog(this);
|
||||||
|
RefreshMainListView();
|
||||||
|
}
|
||||||
private void SelectAll()
|
private void SelectAll()
|
||||||
{
|
{
|
||||||
MainListView.SelectAllItems();
|
MainListView.SelectAllItems();
|
||||||
@ -3007,6 +3107,11 @@ namespace CodeWalker
|
|||||||
DeleteSelected();
|
DeleteSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ListContextDefragmentMenu_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DefragmentSelected();
|
||||||
|
}
|
||||||
|
|
||||||
private void ListContextSelectAllMenu_Click(object sender, EventArgs e)
|
private void ListContextSelectAllMenu_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SelectAll();
|
SelectAll();
|
||||||
@ -3512,33 +3617,4 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 : "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -450,24 +450,6 @@
|
|||||||
AQABAQHAAQEBAAEDAcABAQEAAQEBwAEBAQABAwHAAQEBAAEBAQABAQEAAQcBwAEDAQABAQEAAQEBAAEP
|
AQABAQHAAQEBAAEDAcABAQEAAQEBwAEBAQABAwHAAQEBAAEBAQABAQEAAQcBwAEDAQABAQEAAQEBAAEP
|
||||||
AcABAwEAAQEBAAEBAQABDwHAAQMBAAEBAQABAQEAAQ8BwAEDAQABAQHAAQcBAAEPAcABAwEAAQMB4AEP
|
AcABAwEAAQEBAAEBAQABDwHAAQMBAAEBAQABAQEAAQ8BwAEDAQABAQHAAQcBAAEPAcABAwEAAQMB4AEP
|
||||||
AQABDwHAAQMBAAEHCw==
|
AQABDwHAAQMBAAEHCw==
|
||||||
</value>
|
|
||||||
</data>
|
|
||||||
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
|
||||||
YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAACbSURBVDhPlY/BDYAgDEXZxNWcywsLeXECb45A4kX8n1CC
|
|
||||||
UBCaPFNq6H+YVjnnVuAjaxyPFy6dz7F4wj6Ox4qJ97V5v5sA+ykLSZcFUxZlujBskafjGGA/ZFGmY5QW
|
|
||||||
kF+LPF1b0LUo07UFpGlRphOMqwWqhZbeo7LQ0gl+VQbkY9FLby0gyaKV/keywMfOvF+IBlaeYQEHM+Cy
|
|
||||||
MS8nLPK4Pr55DAAAAABJRU5ErkJggg==
|
|
||||||
</value>
|
|
||||||
</data>
|
|
||||||
<data name="pictureBox2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
|
||||||
YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAC1SURBVDhP3ZO9DUIxDISzBw2bkQWYgGnYA+mJhjYzQIWg
|
|
||||||
eKJJG/yBLb34GSGg46Qr4vOd8uMkj1prFg7C5kgta9scIi6FZTje2mp3bovtqSM1NHroVdsTah7X+8vM
|
|
||||||
6Lk5XAkZuxBZFATfbPB1DSlmzmzNN0FDpOlxMgFDdOZ3xIOXgLABGiIN4v2TgJeXaIi06SX+9ow6CyWa
|
|
||||||
QoOvd4MEZPEY5WgaPcNRBhry3WeaQsQPvnNKd1hjo1V/TdpFAAAAAElFTkSuQmCC
|
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<metadata name="ListContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="ListContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
@ -592,6 +574,24 @@
|
|||||||
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
<value>152, 56</value>
|
<value>152, 56</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
|
YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAACbSURBVDhPlY/BDYAgDEXZxNWcywsLeXECb45A4kX8n1CC
|
||||||
|
UBCaPFNq6H+YVjnnVuAjaxyPFy6dz7F4wj6Ox4qJ97V5v5sA+ykLSZcFUxZlujBskafjGGA/ZFGmY5QW
|
||||||
|
kF+LPF1b0LUo07UFpGlRphOMqwWqhZbeo7LQ0gl+VQbkY9FLby0gyaKV/keywMfOvF+IBlaeYQEHM+Cy
|
||||||
|
MS8nLPK4Pr55DAAAAABJRU5ErkJggg==
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<data name="pictureBox2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||||
|
YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAC1SURBVDhP3ZO9DUIxDISzBw2bkQWYgGnYA+mJhjYzQIWg
|
||||||
|
eKJJG/yBLb34GSGg46Qr4vOd8uMkj1prFg7C5kgta9scIi6FZTje2mp3bovtqSM1NHroVdsTah7X+8vM
|
||||||
|
6Lk5XAkZuxBZFATfbPB1DSlmzmzNN0FDpOlxMgFDdOZ3xIOXgLABGiIN4v2TgJeXaIi06SX+9ow6CyWa
|
||||||
|
QoOvd4MEZPEY5WgaPcNRBhry3WeaQsQPvnNKd1hjo1V/TdpFAAAAAElFTkSuQmCC
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||||
<value>126</value>
|
<value>126</value>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -1216,7 +1216,7 @@ namespace CodeWalker.GameFiles
|
|||||||
var child = FindChildArchive(f);
|
var child = FindChildArchive(f);
|
||||||
if (child != null)
|
if (child != null)
|
||||||
{
|
{
|
||||||
child.StartPos = newstart;
|
child.UpdateStartPos(newstart);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1353,6 +1353,42 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public long GetDefragmentedFileSize()
|
||||||
|
{
|
||||||
|
//this represents the size the file would be when fully defragmented.
|
||||||
|
uint blockcount = GetHeaderBlockCount();
|
||||||
|
|
||||||
|
foreach (var entry in AllEntries)
|
||||||
|
{
|
||||||
|
var fentry = entry as RpfFileEntry;
|
||||||
|
if (fentry != null)
|
||||||
|
{
|
||||||
|
blockcount += GetBlockCount(fentry.GetFileSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (long)blockcount * 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void UpdateStartPos(long newpos)
|
||||||
|
{
|
||||||
|
StartPos = newpos;
|
||||||
|
|
||||||
|
if (Children != null)
|
||||||
|
{
|
||||||
|
//make sure children also get their StartPos updated!
|
||||||
|
foreach (var child in Children)
|
||||||
|
{
|
||||||
|
if (child.ParentFileEntry == null) continue;//shouldn't really happen...
|
||||||
|
var cpos = StartPos + (long)child.ParentFileEntry.FileOffset * 512;
|
||||||
|
child.UpdateStartPos(newpos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static RpfFile CreateNew(string gtafolder, string relpath, RpfEncryption encryption = RpfEncryption.OPEN)
|
public static RpfFile CreateNew(string gtafolder, string relpath, RpfEncryption encryption = RpfEncryption.OPEN)
|
||||||
{
|
{
|
||||||
@ -1733,6 +1769,92 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void Defragment(RpfFile file, Action<string, float> progress)
|
||||||
|
{
|
||||||
|
if (file?.AllEntries == null) return;
|
||||||
|
|
||||||
|
string fpath = file.GetPhysicalFilePath();
|
||||||
|
using (var fstream = File.Open(fpath, FileMode.Open, FileAccess.ReadWrite))
|
||||||
|
{
|
||||||
|
using (var bw = new BinaryWriter(fstream))
|
||||||
|
{
|
||||||
|
uint destblock = file.GetHeaderBlockCount();
|
||||||
|
|
||||||
|
const int BUFFER_SIZE = 16384;//what buffer size is best for HDD copy?
|
||||||
|
var buffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
var allfiles = new List<RpfFileEntry>();
|
||||||
|
for (int i = 0; i < file.AllEntries.Count; i++)
|
||||||
|
{
|
||||||
|
var entry = file.AllEntries[i] as RpfFileEntry;
|
||||||
|
if (entry != null) allfiles.Add(entry);
|
||||||
|
}
|
||||||
|
//make sure we process everything in the current order that they are in the archive
|
||||||
|
allfiles.Sort((a, b) => { return a.FileOffset.CompareTo(b.FileOffset); });
|
||||||
|
|
||||||
|
for (int i = 0; i < allfiles.Count; i++)
|
||||||
|
{
|
||||||
|
var entry = allfiles[i];
|
||||||
|
float prog = (float)i / allfiles.Count;
|
||||||
|
string txt = "Relocating " + entry.Name + "...";
|
||||||
|
progress(txt, prog);
|
||||||
|
|
||||||
|
var sourceblock = entry.FileOffset;
|
||||||
|
var blockcount = GetBlockCount(entry.GetFileSize());
|
||||||
|
|
||||||
|
if (sourceblock > destblock) //should only be moving things toward the start
|
||||||
|
{
|
||||||
|
var source = file.StartPos + (long)sourceblock * 512;
|
||||||
|
var dest = file.StartPos + (long)destblock * 512;
|
||||||
|
var remlength = (long)blockcount * 512;
|
||||||
|
while (remlength > 0)
|
||||||
|
{
|
||||||
|
fstream.Position = source;
|
||||||
|
int n = fstream.Read(buffer, 0, (int)Math.Min(remlength, BUFFER_SIZE));
|
||||||
|
fstream.Position = dest;
|
||||||
|
fstream.Write(buffer, 0, n);
|
||||||
|
source += n;
|
||||||
|
dest += n;
|
||||||
|
remlength -= n;
|
||||||
|
}
|
||||||
|
entry.FileOffset = destblock;
|
||||||
|
|
||||||
|
var entryrpf = file.FindChildArchive(entry);
|
||||||
|
if (entryrpf != null)
|
||||||
|
{
|
||||||
|
entryrpf.UpdateStartPos(file.StartPos + (long)entry.FileOffset * 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sourceblock != destblock)
|
||||||
|
{ }//shouldn't get here...
|
||||||
|
|
||||||
|
destblock += blockcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.FileSize = (long)destblock * 512;
|
||||||
|
|
||||||
|
file.WriteHeader(bw);
|
||||||
|
|
||||||
|
if (file.ParentFileEntry != null)
|
||||||
|
{
|
||||||
|
//make sure to also update the parent archive file entry, if there is one
|
||||||
|
file.ParentFileEntry.FileUncompressedSize = (uint)file.FileSize;
|
||||||
|
file.ParentFileEntry.FileSize = 0;
|
||||||
|
if (file.Parent != null)
|
||||||
|
{
|
||||||
|
file.Parent.WriteHeader(bw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file.Parent == null)
|
||||||
|
{
|
||||||
|
//this is a root archive, so update the file's length to the new size.
|
||||||
|
fstream.SetLength(file.FileSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static string GetParentPath(string path)
|
private static string GetParentPath(string path)
|
||||||
{
|
{
|
||||||
|
@ -422,6 +422,48 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class Prompt
|
||||||
|
{
|
||||||
|
//handy utility to get a string from the user...
|
||||||
|
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
|
||||||
|
};
|
||||||
|
var textLabel = new Label() { Left = 30, Top = 20, Width = 370, Height = 20, Text = text, };
|
||||||
|
var textBox = new TextBox() { Left = 30, Top = 40, Width = 370, Text = defaultvalue };
|
||||||
|
var cancel = new Button() { Text = "Cancel", Left = 230, Width = 80, Top = 70, DialogResult = DialogResult.Cancel };
|
||||||
|
var 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 : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//unused
|
//unused
|
||||||
//public class AccurateTimer
|
//public class AccurateTimer
|
||||||
//{
|
//{
|
||||||
|
Loading…
Reference in New Issue
Block a user