From 1ba9d45b193946272ea33012d50241add11ba14f Mon Sep 17 00:00:00 2001
From: Li
Date: Sun, 5 Mar 2023 13:01:54 +1300
Subject: [PATCH] Add support for EU xbox release
---
LibW4M/W4SaveFile.cs | 8 +--
LibW4M/XBOX/XboxRegion.cs | 15 +++++
LibW4M/XBOX/XboxSave.cs | 66 +++++++++++++++----
W4Gui/DataManager.cs | 1 +
W4Gui/Dialogs/AboutW4Gui.resx | 3 +-
W4Gui/Main.cs | 48 ++++++++++----
.../PublishProfiles/FolderProfile.pubxml.user | 2 +-
W4Gui/SaveType.cs | 9 +--
8 files changed, 118 insertions(+), 34 deletions(-)
create mode 100644 LibW4M/XBOX/XboxRegion.cs
diff --git a/LibW4M/W4SaveFile.cs b/LibW4M/W4SaveFile.cs
index e1bd4ba..1b3832c 100644
--- a/LibW4M/W4SaveFile.cs
+++ b/LibW4M/W4SaveFile.cs
@@ -174,11 +174,11 @@ namespace LibW4M
}
}
- public void SaveXBOX(Stream xboxSaveStream)
+ public void SaveXBOX(Stream xboxSaveStream, XboxRegion region)
{
using (xboxSaveStream)
{
- XboxSave.CreateSaveFile(this, xboxSaveStream);
+ XboxSave.CreateSaveFile(this, xboxSaveStream, region);
}
}
@@ -190,9 +190,9 @@ namespace LibW4M
}
}
- public void SaveXBOX(string newXom)
+ public void SaveXBOX(string newXom, XboxRegion region)
{
- SaveXBOX(File.OpenWrite(newXom));
+ SaveXBOX(File.OpenWrite(newXom), region);
}
public void SavePS2(string newXom)
{
diff --git a/LibW4M/XBOX/XboxRegion.cs b/LibW4M/XBOX/XboxRegion.cs
new file mode 100644
index 0000000..3a163af
--- /dev/null
+++ b/LibW4M/XBOX/XboxRegion.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LibW4M.XBOX
+{
+ public enum XboxRegion : int
+ {
+ USA = 0,
+ EU = 1,
+ UNKNOWN = 2
+ }
+}
diff --git a/LibW4M/XBOX/XboxSave.cs b/LibW4M/XBOX/XboxSave.cs
index 18acba3..239037e 100644
--- a/LibW4M/XBOX/XboxSave.cs
+++ b/LibW4M/XBOX/XboxSave.cs
@@ -16,9 +16,18 @@ namespace LibW4M.XBOX
private const int SHA1_SIZE = 0x14;
private const int XBOX_MAX_SZ = 0x64000;
- public static byte[] XboxSigningKey = new byte[0x40] { 0x20, 0x23, 0x8B, 0x22, 0xED, 0x13, 0xB7, 0xC1, 0x71, 0x5F, 0xC5, 0xB3, 0x72, 0x07, 0xC0, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ public static byte[] GetXboxSigningKeyForRegion(XboxRegion region) {
+ switch (region)
+ {
+ case XboxRegion.EU:
+ return new byte[0x10] { 0x78, 0x9F, 0x93, 0x67, 0xFD, 0xC8, 0x70, 0xAC, 0xCF, 0x9D, 0x46, 0xB0, 0x5E, 0x51, 0x36, 0x43 };
+ case XboxRegion.USA:
+ default:
+ return new byte[0x10] { 0x20, 0x23, 0x8B, 0x22, 0xED, 0x13, 0xB7, 0xC1, 0x71, 0x5F, 0xC5, 0xB3, 0x72, 0x07, 0xC0, 0x24 };
- public static void CreateSaveFile(W4SaveFile save, Stream output)
+ }
+ }
+ public static void CreateSaveFile(W4SaveFile save, Stream output, XboxRegion region)
{
using(MemoryStream ms = new MemoryStream())
{
@@ -32,7 +41,7 @@ namespace LibW4M.XBOX
XomWriter.WriteXom(save.OriginalXom, ms);
ms.Seek(0, SeekOrigin.Begin);
- XboxSave.CalcAndWriteSignature(ms);
+ XboxSave.CalcAndWriteSignature(ms, region);
ms.Seek(0, SeekOrigin.Begin);
ms.CopyTo(output);
@@ -47,14 +56,17 @@ namespace LibW4M.XBOX
return outdata;
}
- private static byte[] calcSignature(byte[] data)
+ private static byte[] calcSignature(byte[] data, XboxRegion region)
{
using (SHA1 sha = SHA1.Create())
{
using (MemoryStream ms = new MemoryStream())
{
+ byte[] signHeader = new byte[0x40];
+ Array.Copy(GetXboxSigningKeyForRegion(region), signHeader, 0x10);
+
// hash save data
- ms.Write(xor(XboxSigningKey, 0x36), 0, XboxSigningKey.Length);
+ ms.Write(xor(signHeader, 0x36), 0, signHeader.Length);
ms.Write(data);
ms.Seek(0, SeekOrigin.Begin);
@@ -65,7 +77,7 @@ namespace LibW4M.XBOX
ms.Seek(0, SeekOrigin.Begin);
ms.SetLength(0);
- ms.Write(xor(XboxSigningKey, 0x5C), 0, XboxSigningKey.Length);
+ ms.Write(xor(signHeader, 0x5C), 0, signHeader.Length);
ms.Write(hash, 0, hash.Length);
sha.Initialize();
@@ -74,21 +86,49 @@ namespace LibW4M.XBOX
}
}
}
-
- public static W4SaveFile ReadXboxSave(string filepath)
+ private static MemoryStream readSaveData(Stream stream)
{
- using (FileStream fs = File.OpenRead(filepath))
+ MemoryStream ms = new MemoryStream();
+ stream.Seek(SHA1_SIZE, SeekOrigin.Begin);
+ stream.CopyTo(ms);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ stream.Seek(0, SeekOrigin.Begin);
+ return ms;
+ }
+
+ public static XboxRegion DetermineRegion(Stream stream)
+ {
+ byte[] expectedSignature = new byte[SHA1_SIZE];
+ stream.Read(expectedSignature, 0, SHA1_SIZE);
+
+ byte[] saveData = new byte[XBOX_MAX_SZ];
+ stream.Read(saveData, 0, XBOX_MAX_SZ);
+
+ stream.Seek(0, SeekOrigin.Begin);
+
+ byte[] usaSig = calcSignature(saveData, XboxRegion.USA);
+ byte[] eurSig = calcSignature(saveData, XboxRegion.EU);
+
+ if (expectedSignature.SequenceEqual(usaSig)) return XboxRegion.USA;
+ else if (expectedSignature.SequenceEqual(eurSig)) return XboxRegion.EU;
+ else return XboxRegion.UNKNOWN;
+
+ }
+
+ public static W4SaveFile ReadXboxSave(Stream stream)
+ {
+ using (MemoryStream ms = readSaveData(stream))
{
- fs.Seek(SHA1_SIZE, SeekOrigin.Begin);
- return new W4SaveFile(XomReader.ReadXomFile(fs));
+ return new W4SaveFile(XomReader.ReadXomFile(ms));
}
}
- public static void CalcAndWriteSignature(Stream s)
+ public static void CalcAndWriteSignature(Stream s, XboxRegion region)
{
byte[] data = new byte[XBOX_MAX_SZ];
s.Read(data, 0, XBOX_MAX_SZ);
- byte[] signature = calcSignature(data);
+ byte[] signature = calcSignature(data, region);
using(MemoryStream ms = new MemoryStream())
{
ms.Write(signature, 0, SHA1_SIZE);
diff --git a/W4Gui/DataManager.cs b/W4Gui/DataManager.cs
index bacfd2e..54486e7 100644
--- a/W4Gui/DataManager.cs
+++ b/W4Gui/DataManager.cs
@@ -1,4 +1,5 @@
using LibW4M;
+using LibW4M.XBOX;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/W4Gui/Dialogs/AboutW4Gui.resx b/W4Gui/Dialogs/AboutW4Gui.resx
index 4770e53..30210af 100644
--- a/W4Gui/Dialogs/AboutW4Gui.resx
+++ b/W4Gui/Dialogs/AboutW4Gui.resx
@@ -61,7 +61,7 @@
iVBORw0KGgoAAAANSUhEUgAAAHgAAAEGCAIAAAAhWcaAAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- wAAADsABataJCQAAZ9BJREFUeF7tvXuUXdV15nvqnH1eVSUhQIAeVVLpLUCgB3ohCRCWAIEFyEY22GDz
+ vAAADrwBlbxySQAAZ9BJREFUeF7tvXuUXdV15nvqnH1eVSUhQIAeVVLpLUCgB3ohCRCWAIEFyEY22GDz
DGDAGPzENrbEGxsTYjsYY4zBBr9ix0+cOMFxnOAOTuwOSZzupOPb7U4naXdfd3f6dm5GMu4/fX9zfmvN
s2qfkiA36XvHHfEenxZzffObc8019z777HOqkBqNG8cabxiz8QbHjaONN4wn26YFf+O4T92LBqbUMIZ4
xmnYimVRm3raAe/G9XmJxLPQuBeZxZYcWxkcyXZZ1CaSURuMqRm5+FRGdmm0nXp+BSKO2oAqkW3151GC
@@ -527,6 +527,7 @@ shadowknight1620
- Reverse Engineering:
Li
+
- Worms 4 Mayhem:
Team17
Codemasters
diff --git a/W4Gui/Main.cs b/W4Gui/Main.cs
index f792691..0d50875 100644
--- a/W4Gui/Main.cs
+++ b/W4Gui/Main.cs
@@ -35,15 +35,17 @@ namespace W4Gui
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
+#if !DEBUG
try
{
+#endif
OpenFileDialog fd = new OpenFileDialog();
fd.Filter = "Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Save File|*.psu|Worms 4: Mayhem XBOX Save File|data";
fd.Title = "Open Worms 4 Save File";
if (fd.ShowDialog() == DialogResult.OK)
{
DataManager.LoadedSavePath = fd.FileName;
- DataManager.LoadedSaveType = (SaveType)(fd.FilterIndex - 1);
+ DataManager.LoadedSaveType = (SaveType)(fd.FilterIndex);
switch (DataManager.LoadedSaveType)
{
@@ -54,8 +56,17 @@ namespace W4Gui
case SaveType.PS2:
DataManager.SaveFile = Ps2Save.ReadPS2Save(fd.FileName);
break;
- case SaveType.XBOX:
- DataManager.SaveFile = XboxSave.ReadXboxSave(fd.FileName);
+ case SaveType.XBOX_US:
+ case SaveType.XBOX_EU:
+ using(FileStream fs = File.OpenRead(fd.FileName))
+ {
+ XboxRegion region = XboxSave.DetermineRegion(fs);
+
+ if (region == XboxRegion.USA) DataManager.LoadedSaveType = SaveType.XBOX_US;
+ if (region == XboxRegion.EU) DataManager.LoadedSaveType = SaveType.XBOX_EU;
+
+ DataManager.SaveFile = XboxSave.ReadXboxSave(fs);
+ }
break;
}
@@ -69,18 +80,21 @@ namespace W4Gui
DataManager.LoadAll();
}
+#if !DEBUG
}
catch (Exception ex)
{
- MessageBox.Show("Failed to load save: " + ex.Message + "\nIt may be invalid or corrupt.", "Load failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ MessageBox.Show("Failed to load save due to an error\n" + ex.Message + "\nThe file may be invalid or corrupt.", "Load failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
-
+#endif
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
+#if !DEBUG
try
{
+#endif
mainTabControl.Enabled = false;
DataManager.SaveAll();
switch (DataManager.LoadedSaveType)
@@ -91,17 +105,22 @@ namespace W4Gui
case SaveType.PS2:
DataManager.SaveFile.SavePS2PSU(DataManager.LoadedSavePath);
break;
- case SaveType.XBOX:
- DataManager.SaveFile.SaveXBOX(DataManager.LoadedSavePath);
+ case SaveType.XBOX_US:
+ DataManager.SaveFile.SaveXBOX(DataManager.LoadedSavePath, XboxRegion.USA);
+ break;
+ case SaveType.XBOX_EU:
+ DataManager.SaveFile.SaveXBOX(DataManager.LoadedSavePath, XboxRegion.EU);
break;
}
mainTabControl.Enabled = true;
MessageBox.Show("File saved to: " + DataManager.LoadedSavePath, "Save Complete!", MessageBoxButtons.OK, MessageBoxIcon.Information);
+#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show("Failed to save: " + ex.Message, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
+#endif
}
private void mainTabControl_SelectedIndexChanged(object sender, EventArgs e)
{
@@ -140,10 +159,12 @@ namespace W4Gui
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
+#if !DEBUG
try
{
+#endif
SaveFileDialog fd = new SaveFileDialog();
- fd.Filter = "Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Single Save File|*.psu|Worms 4: Mayhem XBOX Save File|data";
+ fd.Filter = "Worms 4: Mayhem PC Save File|*.xom|Worms 4: Mayhem PS2 Single Save File|*.psu|Worms 4: Mayhem XBOX United States Save File|data|Worms 4: Mayhem XBOX Europe/Austrailia Save File|data";
fd.Title = "Save Worms 4 Save File";
fd.FileName = Path.GetFileName(DataManager.LoadedSavePath);
if (fd.ShowDialog() == DialogResult.OK)
@@ -151,7 +172,7 @@ namespace W4Gui
this.mainTabControl.Enabled = false;
DataManager.SaveAll();
- SaveType saveType = (SaveType)(fd.FilterIndex - 1);
+ SaveType saveType = (SaveType)(fd.FilterIndex);
switch (saveType)
{
@@ -161,8 +182,11 @@ namespace W4Gui
case SaveType.PS2:
DataManager.SaveFile.SavePS2PSU(fd.FileName);
break;
- case SaveType.XBOX:
- DataManager.SaveFile.SaveXBOX(fd.FileName);
+ case SaveType.XBOX_US:
+ DataManager.SaveFile.SaveXBOX(fd.FileName, XboxRegion.USA);
+ break;
+ case SaveType.XBOX_EU:
+ DataManager.SaveFile.SaveXBOX(fd.FileName, XboxRegion.EU);
break;
}
@@ -172,11 +196,13 @@ namespace W4Gui
MessageBox.Show("File saved to: " + fd.FileName, "Save Complete!", MessageBoxButtons.OK, MessageBoxIcon.Information);
this.mainTabControl.Enabled = true;
}
+#if !DEBUG
}
catch (Exception ex)
{
MessageBox.Show("Failed to save: " + ex.Message, "Save failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
+#endif
}
private void aboutProgramToolStripMenuItem_Click(object sender, EventArgs e)
diff --git a/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user b/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user
index 6ca7310..6801b15 100644
--- a/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user
+++ b/W4Gui/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
-->
- True|2023-03-04T16:20:37.5344385Z;False|2023-03-05T05:11:04.5753179+13:00;True|2023-03-04T13:33:03.9184567+13:00;True|2023-03-04T05:17:31.1862857+13:00;True|2023-03-04T04:40:06.7859106+13:00;True|2023-03-01T11:45:37.3479871+13:00;True|2023-03-01T09:19:31.4651141+13:00;True|2023-02-25T21:53:35.8769435+13:00;True|2023-02-20T23:18:32.2496478+13:00;True|2023-02-19T06:40:54.2502643+13:00;False|2023-02-16T17:57:46.9563146+13:00;True|2023-01-19T20:41:26.7371208+13:00;True|2023-01-15T17:06:35.5919106+13:00;True|2023-01-14T13:57:56.0824690+13:00;True|2023-01-11T22:22:28.8737310+13:00;True|2023-01-11T22:16:55.3469226+13:00;
+ True|2023-03-04T17:13:14.7341877Z;True|2023-03-05T05:34:42.0662279+13:00;True|2023-03-05T05:20:37.5344385+13:00;False|2023-03-05T05:11:04.5753179+13:00;True|2023-03-04T13:33:03.9184567+13:00;True|2023-03-04T05:17:31.1862857+13:00;True|2023-03-04T04:40:06.7859106+13:00;True|2023-03-01T11:45:37.3479871+13:00;True|2023-03-01T09:19:31.4651141+13:00;True|2023-02-25T21:53:35.8769435+13:00;True|2023-02-20T23:18:32.2496478+13:00;True|2023-02-19T06:40:54.2502643+13:00;False|2023-02-16T17:57:46.9563146+13:00;True|2023-01-19T20:41:26.7371208+13:00;True|2023-01-15T17:06:35.5919106+13:00;True|2023-01-14T13:57:56.0824690+13:00;True|2023-01-11T22:22:28.8737310+13:00;True|2023-01-11T22:16:55.3469226+13:00;
\ No newline at end of file
diff --git a/W4Gui/SaveType.cs b/W4Gui/SaveType.cs
index 7b6e0ef..4239e1a 100644
--- a/W4Gui/SaveType.cs
+++ b/W4Gui/SaveType.cs
@@ -6,10 +6,11 @@ using System.Threading.Tasks;
namespace W4Gui
{
- public enum SaveType
+ public enum SaveType : int
{
- PC,
- PS2,
- XBOX
+ PC = 1,
+ PS2 = 2,
+ XBOX_US = 3,
+ XBOX_EU = 4
}
}