cpk-tools/CriPakGUI/CpkPatcher.xaml.cs
2024-12-19 15:05:55 +08:00

335 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using System.Windows.Navigation;
using System.Diagnostics;
using Ookii.Dialogs.Wpf;
using System.Threading;
using System.Windows.Threading;
using LibCPK;
namespace CriPakGUI
{
/// <summary>
/// CpkPatcher.xaml 的交互逻辑
/// </summary>
public partial class CpkPatcher : Window
{
public CpkPatcher(double x, double y)
{
InitializeComponent();
this.WindowStartupLocation = WindowStartupLocation.Manual;
this.Top = x;
this.Left = y;
}
private void button_selPatchPath_Click(object sender, RoutedEventArgs e)
{
VistaFolderBrowserDialog saveFilesDialog = new VistaFolderBrowserDialog();
saveFilesDialog.SelectedPath = myPackage.basePath + "/";
if (saveFilesDialog.ShowDialog().Value)
{
Debug.Print(saveFilesDialog.SelectedPath);
textbox_patchDir.Text = saveFilesDialog.SelectedPath;
}
}
private void button_selDstCPK_Click(object sender, RoutedEventArgs e)
{
VistaSaveFileDialog saveDialog = new VistaSaveFileDialog();
saveDialog.InitialDirectory = myPackage.basePath;
saveDialog.RestoreDirectory = true;
saveDialog.Filter = "CPK File*.cpk|*.cpk";
if (saveDialog.ShowDialog() == true)
{
string saveFileName = saveDialog.FileName;
textbox_cpkDir.Text = saveFileName;
}
}
private delegate void textblockDelegate(string text);
private void updateTextblock(string text)
{
textblock0.Text += string.Format("Updating ... {0}\n", text);
scrollview0.ScrollToEnd();
}
private delegate void progressbarDelegate(float no);
private void updateprogressbar(float no)
{
progressbar1.Value = no;
}
public class actionCPK
{
public string cpkDir { get; set; }
public string patchDir { get; set; }
public bool bForceCompress { get; set; }
public Dictionary<string, string> batch_file_list { get; set; }
}
private void button_PatchCPK_Click(object sender, RoutedEventArgs e)
{
string cpkDir = textbox_cpkDir.Text;
string patchDir = textbox_patchDir.Text;
Dictionary<string, string> batch_file_list = new Dictionary<string, string>();
List<string> ls = new List<string>();
if ((myPackage.cpk != null) && (Directory.Exists(patchDir)))
{
GetFilesFromPath(patchDir, ref ls);
Debug.Print(string.Format("GOT {0} Files.", ls.Count));
foreach (string s in ls)
{
string name = s.Remove(0, patchDir.Length + 1);
name = name.Replace("\\" , @"/");
if (!name.Contains(@"/"))
{
name = @"/" + name;
}
batch_file_list.Add(name, s);
}
actionCPK t = new actionCPK();
t.cpkDir = cpkDir;
t.patchDir = patchDir;
if (checkbox_donotcompress.IsChecked == true)
{
t.bForceCompress = false;
}
else
{
t.bForceCompress = true;
}
t.batch_file_list = batch_file_list;
ThreadPool.QueueUserWorkItem(new WaitCallback(PatchCPK), t);
}
else
{
MessageBox.Show("Error, cpkdata or patchdata not found.");
}
}
private void PatchCPK(object t)
{
string msg;
string cpkDir = ((actionCPK)t).cpkDir;
string patchDir = ((actionCPK)t).patchDir;
bool bForceCompress = ((actionCPK)t).bForceCompress;
Dictionary<string, string> batch_file_list = ((actionCPK)t).batch_file_list;
CPK cpk = myPackage.cpk;
BinaryReader oldFile = new BinaryReader(File.OpenRead(myPackage.cpk_name));
string outputName = cpkDir;
BinaryWriter newCPK = new BinaryWriter(File.OpenWrite(outputName));
List<FileEntry> entries = cpk.FileTable.OrderBy(x => x.FileOffset).ToList();
Tools tool = new Tools();
int id;
bool bFileRepeated = Tools.CheckListRedundant(entries);
for (int i = 0; i < entries.Count; i++)
{
this.UI_SetProgess((float)i / (float)entries.Count * 100f);
if (entries[i].FileType != "CONTENT")
{
if (entries[i].FileType == "FILE")
{
// I'm too lazy to figure out how to update the ContextOffset position so this works :)
if ((ulong)newCPK.BaseStream.Position < cpk.ContentOffset)
{
ulong padLength = cpk.ContentOffset - (ulong)newCPK.BaseStream.Position;
for (ulong z = 0; z < padLength; z++)
{
newCPK.Write((byte)0);
}
}
}
id = Convert.ToInt32(entries[i].ID);
string currentName;
if (id > 0 && bFileRepeated)
{
currentName = (((entries[i].DirName != null) ?
entries[i].DirName + "/" : "") + string.Format("[{0}]", id.ToString()) + entries[i].FileName);
}
else
{
currentName = ((entries[i].DirName != null) ? entries[i].DirName + "/" : "") + entries[i].FileName;
}
if (!currentName.Contains("/"))
{
currentName = "/" + currentName;
}
Debug.Print("Got File:" + currentName.ToString());
if (!batch_file_list.Keys.Contains(currentName.ToString()))
//如果不在表中,复制原始数据
{
oldFile.BaseStream.Seek((long)entries[i].FileOffset, SeekOrigin.Begin);
entries[i].FileOffset = (ulong)newCPK.BaseStream.Position;
if (entries[i].FileName.ToString() == "ETOC_HDR")
{
cpk.EtocOffset = entries[i].FileOffset;
Debug.Print("Fix ETOC_OFFSET to {0:x8}", cpk.EtocOffset);
}
cpk.UpdateFileEntry(entries[i]);
byte[] chunk = oldFile.ReadBytes(Int32.Parse(entries[i].FileSize.ToString()));
newCPK.Write(chunk);
if ((newCPK.BaseStream.Position % 0x800) > 0 && i < entries.Count - 1)
{
long cur_pos = newCPK.BaseStream.Position;
for (int j = 0; j < (0x800 - (cur_pos % 0x800)); j++)
{
newCPK.Write((byte)0);
}
}
}
else
{
string replace_with = batch_file_list[currentName.ToString()];
//Got patch file name
msg = string.Format("Patching: {0}", currentName.ToString());
this.UI_SetTextBlock(msg);
Debug.Print(msg);
byte[] newbie = File.ReadAllBytes(replace_with);
entries[i].FileOffset = (ulong)newCPK.BaseStream.Position;
int o_ext_size = Int32.Parse((entries[i].ExtractSize).ToString());
int o_com_size = Int32.Parse((entries[i].FileSize).ToString());
if ((o_com_size < o_ext_size) && entries[i].FileType == "FILE" && bForceCompress == true)
{
// is compressed
msg = string.Format("Compressing data:{0:x8}", newbie.Length);
this.UI_SetTextBlock(msg);
Console.Write(msg);
byte[] dest_comp = cpk.CompressCRILAYLA(newbie);
entries[i].FileSize = Convert.ChangeType(dest_comp.Length, entries[i].FileSizeType);
entries[i].ExtractSize = Convert.ChangeType(newbie.Length, entries[i].FileSizeType);
cpk.UpdateFileEntry(entries[i]);
newCPK.Write(dest_comp);
msg = string.Format(">> {0:x8}\r\n", dest_comp.Length);
this.UI_SetTextBlock(msg);
Console.Write(msg);
}
else
{
msg = string.Format("Storing data:{0:x8}\r\n", newbie.Length);
this.UI_SetTextBlock(msg);
Console.Write(msg);
entries[i].FileSize = Convert.ChangeType(newbie.Length, entries[i].FileSizeType);
entries[i].ExtractSize = Convert.ChangeType(newbie.Length, entries[i].FileSizeType);
cpk.UpdateFileEntry(entries[i]);
newCPK.Write(newbie);
}
if ((newCPK.BaseStream.Position % 0x800) > 0 && i < entries.Count - 1)
{
long cur_pos = newCPK.BaseStream.Position;
for (int j = 0; j < (0x800 - (cur_pos % 0x800)); j++)
{
newCPK.Write((byte)0);
}
}
}
}
else
{
// Content is special.... just update the position
cpk.UpdateFileEntry(entries[i]);
}
}
cpk.WriteCPK(newCPK);
msg = string.Format("Writing TOC....");
this.UI_SetTextBlock(msg);
Console.WriteLine(msg);
cpk.WriteITOC(newCPK);
cpk.WriteTOC(newCPK);
cpk.WriteETOC(newCPK, cpk.EtocOffset);
cpk.WriteGTOC(newCPK);
newCPK.Close();
oldFile.Close();
msg = string.Format("Saving CPK to {0}....", outputName);
this.UI_SetTextBlock(msg);
Console.WriteLine(msg);
MessageBox.Show("CPK Patched.");
this.UI_SetProgess(0f);
}
public void UI_SetProgess(float value)
{
this.Dispatcher.Invoke(new progressbarDelegate(updateprogressbar), new object[] { (float)value });
}
public void UI_SetTextBlock(string msg)
{
this.Dispatcher.Invoke(new textblockDelegate(updateTextblock), new object[] { msg });
}
private void GetFilesFromPath(string directoryname , ref List<string> ls)
{
FileInfo[] fi = new DirectoryInfo(directoryname).GetFiles();
DirectoryInfo[] di = new DirectoryInfo(directoryname).GetDirectories();
if (fi.Length != 0)
{
foreach (FileInfo v in fi)
{
ls.Add(v.FullName);
}
}
if (di.Length != 0)
{
foreach (DirectoryInfo v in di)
{
GetFilesFromPath(v.FullName , ref ls);
}
}
}
}
}