From 08ab953bffc4f0353f10e0e4f4513fac9555a3bf Mon Sep 17 00:00:00 2001 From: morkt Date: Mon, 25 Sep 2023 21:02:56 +0400 Subject: [PATCH] (ArcNE): parse VERSION resource. --- Experimental/Microsoft/ArcEXE.cs | 12 ++-- Experimental/Microsoft/ArcNE.cs | 98 +++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 16 deletions(-) diff --git a/Experimental/Microsoft/ArcEXE.cs b/Experimental/Microsoft/ArcEXE.cs index 56ca88ad..4c5b4230 100644 --- a/Experimental/Microsoft/ArcEXE.cs +++ b/Experimental/Microsoft/ArcEXE.cs @@ -37,11 +37,11 @@ namespace GameRes.Formats.Microsoft [ExportMetadata("Priority", -1)] public class ExeOpener : ArchiveFormat { - public override string Tag { get => "EXE"; } - public override string Description { get => "Windows executable resources"; } - public override uint Signature { get => 0; } - public override bool IsHierarchic { get => true; } - public override bool CanWrite { get => false; } + public override string Tag => "EXE"; + public override string Description => "Windows executable resources"; + public override uint Signature => 0; + public override bool IsHierarchic => true; + public override bool CanWrite => false; public ExeOpener () { @@ -158,8 +158,6 @@ namespace GameRes.Formats.Microsoft return id; } - static readonly byte[] VS_VERSION_INFO = Encoding.Unicode.GetBytes ("VS_VERSION_INFO"); - Stream OpenVersion (byte[] data, string name) { var input = new BinMemoryStream (data, name); diff --git a/Experimental/Microsoft/ArcNE.cs b/Experimental/Microsoft/ArcNE.cs index ba795e57..88a8b599 100644 --- a/Experimental/Microsoft/ArcNE.cs +++ b/Experimental/Microsoft/ArcNE.cs @@ -27,17 +27,19 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using System.Text; namespace GameRes.Formats.Microsoft { [Export(typeof(ArchiveFormat))] - public class PakOpener : ArchiveFormat + [ExportMetadata("Priority", -2)] + public class NeExeOpener : ArchiveFormat { - public override string Tag { get => "EXE/NE"; } - public override string Description { get => "Windows 16-bit executable resources"; } - public override uint Signature { get => 0; } - public override bool IsHierarchic { get => true; } - public override bool CanWrite { get => false; } + public override string Tag => "EXE/NE"; + public override string Description => "Windows 16-bit executable resources"; + public override uint Signature => 0; + public override bool IsHierarchic => true; + public override bool CanWrite => false; static readonly Dictionary TypeMap = new Dictionary { { 1, "RT_CURSOR" }, @@ -53,10 +55,10 @@ namespace GameRes.Formats.Microsoft public override ArcFile TryOpen (ArcView file) { - if (!file.View.AsciiEqual (0, "MZ")) + if (!file.View.AsciiEqual (0, "MZ") || file.MaxOffset < 0x40) return null; uint ne_offset = file.View.ReadUInt32 (0x3C); - if (!file.View.AsciiEqual (ne_offset, "NE")) + if (ne_offset > file.MaxOffset-2 || !file.View.AsciiEqual (ne_offset, "NE")) return null; uint res_table_offset = file.View.ReadUInt16 (ne_offset+0x24) + ne_offset; if (res_table_offset <= ne_offset || res_table_offset >= file.MaxOffset) @@ -84,13 +86,17 @@ namespace GameRes.Formats.Microsoft int offset = file.View.ReadUInt16 (res_table_offset) << shift; uint size = (uint)file.View.ReadUInt16 (res_table_offset+2) << shift; int res_id = file.View.ReadUInt16 (res_table_offset+6); + if ((res_id & 0x8000) != 0) + res_id &= 0x7FFF; res_table_offset += 12; string name = res_id.ToString ("D5"); name = string.Join ("/", dir_name, name); - var entry = new Entry { + var entry = new NeResourceEntry { Name = name, Offset = offset, Size = size, + NativeName = res_id, + NativeType = type_id, }; dir.Add (entry); } @@ -99,5 +105,79 @@ namespace GameRes.Formats.Microsoft return null; return new ArcFile (file, this, dir); } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var rent = (NeResourceEntry)entry; + if (rent.NativeType == 16) + return OpenVersion (arc, rent); + return base.OpenEntry (arc, entry); + } + + Encoding DefaultEncoding = Encodings.cp932; + + Stream OpenVersion (ArcFile arc, NeResourceEntry entry) + { + uint data_length = arc.File.View.ReadUInt16 (entry.Offset); + var input = arc.File.CreateStream (entry.Offset, data_length); + for (;;) + { + input.ReadUInt16(); + int value_length = input.ReadUInt16(); + if (0 == value_length) + break; + if (input.ReadCString (DefaultEncoding) != "VS_VERSION_INFO") + break; + long pos = (input.Position + 3) & -4L; + input.Position = pos; + if (input.ReadUInt32() != 0xFEEF04BDu) + break; + input.Position = pos + value_length; + int str_info_length = input.ReadUInt16(); + value_length = input.ReadUInt16(); + if (value_length != 0) + break; + if (input.ReadCString (DefaultEncoding) != "StringFileInfo") + break; + pos = (input.Position + 3) & -4L; + input.Position = pos; + int info_length = input.ReadUInt16(); + long end_pos = pos + info_length; + value_length = input.ReadUInt16(); + if (value_length != 0) + break; + var output = new MemoryStream(); + using (var text = new StreamWriter (output, DefaultEncoding, 512, true)) + { + string block_name = input.ReadCString (DefaultEncoding); + text.WriteLine ("BLOCK \"{0}\"\n{{", block_name); + long next_pos = (input.Position + 3) & -4L; + while (next_pos < end_pos) + { + input.Position = next_pos; + info_length = input.ReadUInt16(); + value_length = input.ReadUInt16(); + next_pos = (next_pos + info_length + 3) & -4L; + string key = input.ReadCString (DefaultEncoding); + input.Position = (input.Position + 3) & -4L; + string value = value_length != 0 ? input.ReadCString (value_length, DefaultEncoding) + : String.Empty; + text.WriteLine ("\tVALUE \"{0}\", \"{1}\"", key, value); + } + text.WriteLine ("}"); + } + input.Dispose(); + output.Position = 0; + return output; + } + input.Position = 0; + return input; + } + } + + internal class NeResourceEntry : Entry + { + public int NativeType; + public int NativeName; } }