From 7b71d7b4bf5bc33279cb3513bc0d4ed871e98f73 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 11 Sep 2021 21:41:17 -0700 Subject: [PATCH] Fix resource parsing, fix MS-CAB SFX --- .../Microsoft/Resources/Resource.cs | 14 +---------- .../Microsoft/Resources/StringFileInfo.cs | 22 ++++++++--------- .../Microsoft/Resources/StringStruct.cs | 24 ++++++++----------- .../Microsoft/Resources/StringTable.cs | 22 ++++++++--------- .../ExecutableType/Microsoft/Resources/Var.cs | 22 ++++++++--------- .../Microsoft/Resources/VarFileInfo.cs | 22 ++++++++--------- .../Microsoft/Resources/VersionInfo.cs | 24 +++++++++---------- BurnOutSharp/PackerType/MicrosoftCABSFX.cs | 21 ++++++++++++---- BurnOutSharp/Tools/Extensions.cs | 22 +++++++---------- 9 files changed, 88 insertions(+), 105 deletions(-) diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/Resource.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/Resource.cs index 1c7b0ee2..2dc8fdf8 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/Resource.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/Resource.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using System.IO; using System.Text; using BurnOutSharp.Tools; @@ -37,7 +35,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources while ((r.Length = stream.ReadUInt16()) == 0x0000); - r.Length = stream.ReadUInt16(); r.ValueLength = stream.ReadUInt16(); r.Type = stream.ReadUInt16(); r.Key = stream.ReadString(Encoding.Unicode); @@ -51,18 +48,9 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources while ((r.Length = content.ReadUInt16(ref offset)) == 0x0000); - offset += 2; r.ValueLength = content.ReadUInt16(ref offset); r.Type = content.ReadUInt16(ref offset); - - List keyChars = new List(); - while (BitConverter.ToUInt16(content, offset) != 0x0000) - { - keyChars.Add(Encoding.Unicode.GetChars(content, offset, 2)[0]); offset += 2; - } - offset += 2; - - r.Key = new string(keyChars.ToArray()); + r.Key = content.ReadString(ref offset, Encoding.Unicode); return r; } diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/StringFileInfo.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/StringFileInfo.cs index 7c558a15..b33e67c1 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/StringFileInfo.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/StringFileInfo.cs @@ -10,18 +10,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources /// public StringTable Children; + public StringFileInfo(Resource resource) + { + this.Length = resource?.Length ?? default; + this.ValueLength = resource?.ValueLength ?? default; + this.Type = resource?.Type ?? default; + this.Key = resource?.Key ?? default; + } + public static new StringFileInfo Deserialize(Stream stream) { - StringFileInfo sfi = new StringFileInfo(); - Resource resource = Resource.Deserialize(stream); if (resource.Key != "StringFileInfo") return null; - sfi.Length = resource.Length; - sfi.ValueLength = resource.ValueLength; - sfi.Type = resource.Type; - sfi.Key = resource.Key; + StringFileInfo sfi = new StringFileInfo(resource); sfi.Children = StringTable.Deserialize(stream); return sfi; @@ -29,16 +32,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources public static new StringFileInfo Deserialize(byte[] content, ref int offset) { - StringFileInfo sfi = new StringFileInfo(); - Resource resource = Resource.Deserialize(content, ref offset); if (resource.Key != "StringFileInfo") return null; - sfi.Length = resource.Length; - sfi.ValueLength = resource.ValueLength; - sfi.Type = resource.Type; - sfi.Key = resource.Key; + StringFileInfo sfi = new StringFileInfo(resource); sfi.Children = StringTable.Deserialize(content, ref offset); return sfi; diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/StringStruct.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/StringStruct.cs index f14f7acb..ce4c16dd 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/StringStruct.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/StringStruct.cs @@ -11,16 +11,18 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources /// public string Value; + public StringStruct(Resource resource) + { + this.Length = resource?.Length ?? default; + this.ValueLength = resource?.ValueLength ?? default; + this.Type = resource?.Type ?? default; + this.Key = resource?.Key ?? default; + } + public static new StringStruct Deserialize(Stream stream) { - StringStruct s = new StringStruct(); - Resource resource = Resource.Deserialize(stream); - - s.Length = resource.Length; - s.ValueLength = resource.ValueLength; - s.Type = resource.Type; - s.Key = resource.Key; + StringStruct s = new StringStruct(resource); stream.Seek(stream.Position % 4 == 0 ? 0 : 4 - (stream.Position % 4), SeekOrigin.Current); s.Value = new string(stream.ReadChars(s.ValueLength)); @@ -29,14 +31,8 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources public static new StringStruct Deserialize(byte[] content, ref int offset) { - StringStruct s = new StringStruct(); - Resource resource = Resource.Deserialize(content, ref offset); - - s.Length = resource.Length; - s.ValueLength = resource.ValueLength; - s.Type = resource.Type; - s.Key = resource.Key; + StringStruct s = new StringStruct(resource); offset += offset % 4 == 0 ? 0 : 4 - (offset % 4); s.Value = Encoding.Unicode.GetString(content, offset, s.ValueLength * 2); offset += s.ValueLength * 2; diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/StringTable.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/StringTable.cs index 7a763160..7facdc24 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/StringTable.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/StringTable.cs @@ -10,19 +10,22 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources /// public StringStruct[] Children; + public StringTable(Resource resource) + { + this.Length = resource?.Length ?? default; + this.ValueLength = resource?.ValueLength ?? default; + this.Type = resource?.Type ?? default; + this.Key = resource?.Key ?? default; + } + public static new StringTable Deserialize(Stream stream) { long originalPosition = stream.Position; - StringTable st = new StringTable(); - Resource resource = Resource.Deserialize(stream); if (resource.Key.Length != 8) return null; - st.Length = resource.Length; - st.ValueLength = resource.ValueLength; - st.Type = resource.Type; - st.Key = resource.Key; + StringTable st = new StringTable(resource); var tempValue = new List(); while (stream.Position - originalPosition < st.Length) @@ -38,16 +41,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources public static new StringTable Deserialize(byte[] content, ref int offset) { int originalPosition = offset; - StringTable st = new StringTable(); - Resource resource = Resource.Deserialize(content, ref offset); if (resource.Key.Length != 8) return null; - st.Length = resource.Length; - st.ValueLength = resource.ValueLength; - st.Type = resource.Type; - st.Key = resource.Key; + StringTable st = new StringTable(resource); var tempValue = new List(); while (offset - originalPosition < st.Length) diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/Var.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/Var.cs index 63d9688b..02de3861 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/Var.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/Var.cs @@ -16,19 +16,22 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources /// public LanguageCodePage[] Value; + public Var(Resource resource) + { + this.Length = resource?.Length ?? default; + this.ValueLength = resource?.ValueLength ?? default; + this.Type = resource?.Type ?? default; + this.Key = resource?.Key ?? default; + } + public static new Var Deserialize(Stream stream) { long originalPosition = stream.Position; - Var v = new Var(); - Resource resource = Resource.Deserialize(stream); if (resource.Key != "Translation") return null; - v.Length = resource.Length; - v.ValueLength = resource.ValueLength; - v.Type = resource.Type; - v.Key = resource.Key; + Var v = new Var(resource); var tempValue = new List(); while (stream.Position - originalPosition < v.Length) @@ -44,16 +47,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources public static new Var Deserialize(byte[] content, ref int offset) { int originalPosition = offset; - Var v = new Var(); - Resource resource = Resource.Deserialize(content, ref offset); if (resource.Key != "Translation") return null; - v.Length = resource.Length; - v.ValueLength = resource.ValueLength; - v.Type = resource.Type; - v.Key = resource.Key; + Var v = new Var(resource); var tempValue = new List(); while (offset - originalPosition < v.Length) diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/VarFileInfo.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/VarFileInfo.cs index b44773a0..36395204 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/VarFileInfo.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/VarFileInfo.cs @@ -9,18 +9,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources /// public Var Children; + public VarFileInfo(Resource resource) + { + this.Length = resource?.Length ?? default; + this.ValueLength = resource?.ValueLength ?? default; + this.Type = resource?.Type ?? default; + this.Key = resource?.Key ?? default; + } + public static new VarFileInfo Deserialize(Stream stream) { - VarFileInfo vfi = new VarFileInfo(); - Resource resource = Resource.Deserialize(stream); if (resource.Key != "VarFileInfo") return null; - vfi.Length = resource.Length; - vfi.ValueLength = resource.ValueLength; - vfi.Type = resource.Type; - vfi.Key = resource.Key; + VarFileInfo vfi = new VarFileInfo(resource); vfi.Children = Var.Deserialize(stream); return vfi; @@ -28,16 +31,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources public static new VarFileInfo Deserialize(byte[] content, ref int offset) { - VarFileInfo vfi = new VarFileInfo(); - Resource resource = Resource.Deserialize(content, ref offset); if (resource.Key != "VarFileInfo") return null; - vfi.Length = resource.Length; - vfi.ValueLength = resource.ValueLength; - vfi.Type = resource.Type; - vfi.Key = resource.Key; + VarFileInfo vfi = new VarFileInfo(resource); vfi.Children = Var.Deserialize(content, ref offset); return vfi; diff --git a/BurnOutSharp/ExecutableType/Microsoft/Resources/VersionInfo.cs b/BurnOutSharp/ExecutableType/Microsoft/Resources/VersionInfo.cs index a8027aa0..f09d2f05 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Resources/VersionInfo.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Resources/VersionInfo.cs @@ -23,19 +23,22 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources /// public VarFileInfo ChildrenVarFileInfo; + public VersionInfo(Resource resource) + { + this.Length = resource?.Length ?? default; + this.ValueLength = resource?.ValueLength ?? default; + this.Type = resource?.Type ?? default; + this.Key = resource?.Key ?? default; + } + public static new VersionInfo Deserialize(Stream stream) { long originalPosition = stream.Position; - - VersionInfo vi = new VersionInfo(); Resource resource = Resource.Deserialize(stream); if (resource.Key != "VS_VERSION_INFO") return null; - - vi.Length = resource.Length; - vi.ValueLength = resource.ValueLength; - vi.Type = resource.Type; - vi.Key = resource.Key; + + VersionInfo vi = new VersionInfo(resource); if (vi.ValueLength > 0) vi.Value = FixedFileInfo.Deserialize(stream); @@ -78,16 +81,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Resources public static new VersionInfo Deserialize(byte[] content, ref int offset) { int originalOffset = offset; - - VersionInfo vi = new VersionInfo(); Resource resource = Resource.Deserialize(content, ref offset); if (resource.Key != "VS_VERSION_INFO") return null; - vi.Length = resource.Length; - vi.ValueLength = resource.ValueLength; - vi.Type = resource.Type; - vi.Key = resource.Key; + VersionInfo vi = new VersionInfo(resource); if (vi.ValueLength > 0) vi.Value = FixedFileInfo.Deserialize(content, ref offset); diff --git a/BurnOutSharp/PackerType/MicrosoftCABSFX.cs b/BurnOutSharp/PackerType/MicrosoftCABSFX.cs index 01b7ccfc..5cee2970 100644 --- a/BurnOutSharp/PackerType/MicrosoftCABSFX.cs +++ b/BurnOutSharp/PackerType/MicrosoftCABSFX.cs @@ -24,11 +24,11 @@ namespace BurnOutSharp.PackerType string name = Utilities.GetInternalName(pex); if (!string.IsNullOrWhiteSpace(name) && name.Equals("Wextract", StringComparison.OrdinalIgnoreCase)) - return $"Microsoft CAB SFX v{Utilities.GetFileVersion(pex)}".TrimEnd('v'); + return $"Microsoft CAB SFX {GetVersion(pex)}"; name = Utilities.GetOriginalFileName(pex); if (!string.IsNullOrWhiteSpace(name) && name.Equals("WEXTRACT.EXE", StringComparison.OrdinalIgnoreCase)) - return $"Microsoft CAB SFX v{Utilities.GetFileVersion(pex)}".TrimEnd('v'); + return $"Microsoft CAB SFX {GetVersion(pex)}"; // Get the .data section, if it exists if (pex.DataSectionRaw != null) @@ -45,7 +45,7 @@ namespace BurnOutSharp.PackerType string match = MatchUtil.GetFirstMatch(file, pex.DataSectionRaw, matchers, includeDebug); if (!string.IsNullOrWhiteSpace(match)) - return $"Microsoft CAB SFX v{Utilities.GetFileVersion(pex)}".TrimEnd('v'); + return $"Microsoft CAB SFX {GetVersion(pex)}"; } // Get the .text section, if it exists @@ -61,7 +61,7 @@ namespace BurnOutSharp.PackerType string match = MatchUtil.GetFirstMatch(file, pex.TextSectionRaw, matchers, includeDebug); if (!string.IsNullOrWhiteSpace(match)) - return $"Microsoft CAB SFX v{Utilities.GetFileVersion(pex)}".TrimEnd('v'); + return $"Microsoft CAB SFX {GetVersion(pex)}"; } return null; @@ -84,5 +84,18 @@ namespace BurnOutSharp.PackerType { return null; } + + private string GetVersion(PortableExecutable pex) + { + string version = Utilities.GetFileVersion(pex); + if (!string.IsNullOrWhiteSpace(version)) + return $"v{version}"; + + version = Utilities.GetManifestVersion(pex); + if (!string.IsNullOrWhiteSpace(version)) + return $"v{version}"; + + return string.Empty; + } } } diff --git a/BurnOutSharp/Tools/Extensions.cs b/BurnOutSharp/Tools/Extensions.cs index 7343af41..2323088f 100644 --- a/BurnOutSharp/Tools/Extensions.cs +++ b/BurnOutSharp/Tools/Extensions.cs @@ -126,21 +126,17 @@ namespace BurnOutSharp.Tools /// public static string ReadString(this byte[] content, ref int offset, Encoding encoding) { - // TODO: Fix the code below to make it work with byte arrays and not streams - return null; + byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' }); + int charWidth = nullTerminator.Length; - // byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' }); - // int charWidth = nullTerminator.Length; + List keyChars = new List(); + while (BitConverter.ToUInt16(content, offset) != 0x0000) + { + keyChars.Add(encoding.GetChars(content, offset, charWidth)[0]); offset += charWidth; + } + offset += 2; - // List tempBuffer = new List(); - - // byte[] buffer = new byte[charWidth]; - // while (stream.Read(buffer, 0, charWidth) != 0 && buffer.SequenceEqual(nullTerminator)) - // { - // tempBuffer.AddRange(buffer); - // } - - // return encoding.GetString(tempBuffer.ToArray()); + return new string(keyChars.ToArray()); } ///