c# - 使用正确的编码读取固定的字符数组

标签 c# encoding struct unsafe

我正在尝试为由 Infinity Engine 创建的游戏(博德之门、planescape Torment 等)开发一个修改工具。我知道 Infinity Engine 文件中有什么样的数据结构,我正在从 byte[] 内容映射一些对象。然而,它缺乏一些性能,我对此并不满意。

我在托管世界上的映射对象是结构,我知道它们代表了多少字节。因此我决定在不安全的代码中进行映射过程。我对 Uint 没有任何问题,ushort 就像值类型的值但是在字符串类型中我遇到了 char[] 编码问题。

举个例子,你可以在c#中看到struct gam文件的Header,

http://iesdp.gibberlings3.net/file_formats/ie_formats/gam_v2.0.htm

[StructLayout(LayoutKind.Explicit, Size = 180,CharSet = CharSet.Ansi)]
public unsafe struct Header
{
    [FieldOffset(0)] 
    public fixed char Signature[4];

    [FieldOffset(0x0004)]
    public fixed char Version[4];

    [FieldOffset(0x0008)] public uint GameTime;

    [FieldOffset(0x000c)] public ushort SelectedFormation;

    [FieldOffset(0x000e)] public ushort FormationButton1;

    [FieldOffset(0x0010)] public ushort FormationButton2;

    [FieldOffset(0x0012)] public ushort FormationButton3;

    [FieldOffset(0x0014)] public ushort FormationButton4;

    [FieldOffset(0x0016)] public ushort FormationButton5;

    [FieldOffset(0x0018)] public uint PartyGold;

    [FieldOffset(0x001c)] public ushort NpcStructCountForPartyEx;

    [FieldOffset(0x001e)] public ushort WeatherBitfield;

    [FieldOffset(0x0020)] public uint NpcStructOffsetForParty;

    [FieldOffset(0x0024)] public uint NpcStructCountForPartyInc;

    [FieldOffset(0x0028)] public uint Unknown1;

    [FieldOffset(0x002c)] public uint Unknown2;

    [FieldOffset(0x0030)] public uint NpcStructOffsetForNonParty;

    [FieldOffset(0x0034)] public uint NpcStructCountForNonParty;

    [FieldOffset(0x0038)] public uint GlobalNamespaceVarOffset;

    [FieldOffset(0x003c)] public uint GlobalNamespaceVarCount;

    [FieldOffset(0x0040)] public fixed char MainArea[8];

    [FieldOffset(0x0048)] public uint FamilarExtraOffset;

    [FieldOffset(0x004c)] public uint JournalEntriesCount;

    [FieldOffset(0x0050)] public uint JournalEntriesOffset;

    [FieldOffset(0x0054)] public uint PartyReputation;

    [FieldOffset(0x0058)] public fixed char CurrentArea [8];

    [FieldOffset(0x0060)] public uint GuiFlags;

    [FieldOffset(0x0064)] public uint LoadingProgress;

    [FieldOffset(0x0068)] public uint FamilarInfoOffset;

    [FieldOffset(0x006c)] public uint StoredLocOffset;

    [FieldOffset(0x0070)] public uint StoredLocCount;

    [FieldOffset(0x0074)] public uint GameTimeSec;

    [FieldOffset(0x0078)] public uint PocketPlaneOffset;

    [FieldOffset(0x007c)] public uint PocketPlaneCount;

    [FieldOffset(0x0080)] public fixed byte Unknown3 [52];
}

这就是映射 this 对象的方式;

        string path = @"C:\Baldur.gam";

        byte[] content = IoHelper.ReadBinaryFile(path);

        unsafe
        {
            fixed (byte* pointContent = content)
            {
                Header* header = (Header*) pointContent; 
            }
        }

这是我拥有的 char Signature 的结果;

[0] = 21057 '封' [1] = 13624 '㔸'

这些字符确实不合理。我想这是由编码引起的。有谁知道这个的解决方案?或者我必须自己用 Encoding.ASCII.GetString 读取字符数组吗?如果我用这种方法读取特定大小的 byte[],我会得到真实的结果。

这些结构也有不同的版本。上面的示例中有一个 V.2.0 版本的 Baldur's Gate 2 Gam 文件。但是在 Baldur's Gate 1 中,版本更改为 v.1.0,这不适用于我的方法。我想读取这些不同的方法并将它们映射到模型中,然后将它们发送回 UI 层。您对阅读不同类型的版本有什么建议吗?

提前致谢。

最佳答案

我解决了我的问题。

我问过的人说;

“在 .net 中,char 的长度为 2 个字节。如果直接转换,则无法执行此操作。为此,您可以使用 Marshall 类 PtrToStructureMethod”

我将固定字节成员替换为字符串并使用 MarshalAs 属性,如 ;

    [FieldOffset(0x0004), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string Version;

并将我的映射代码替换为 ;

        string path = @"G:\Games\BGOrg\BGII - SoA\save\000000001-Quick-Save\Baldur.gam";

        byte[] content = IoHelper.ReadBinaryFile(path);

        IntPtr unmanagedPointer = Marshal.AllocHGlobal(content.Length);
        Marshal.Copy(content, 0, unmanagedPointer, content.Length);

        Header header = (Header) Marshal.PtrToStructure(unmanagedPointer, typeof (Header));

工作起来很有魅力:)

问候。

关于c# - 使用正确的编码读取固定的字符数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11820211/

相关文章:

c# - 外键问题(将实体种子添加到 'Comment' 并指定外键值 {'DocumentId' }。)EF

python - python/nautilus 脚本组合的奇怪字符编码问题

c++初始化一个带有数组的结构类型

c++ - 如何修改通过引用传递的结构?

c# - 云服务到 Service Fabric 身份验证?

c# - 根据 C# 中的条件从 List<T> 中删除重复项

c# - 在 C# webBrowser 控件中调用 Javascript 函数

python - 编码 : utf-8 doesn't seem to work

ios - 如何导致NSString的dataUsingEncoding : method return nil?

c - Overeager struct packing warnings with `__attribute__((packed))` ?