SkyrimのModをプログラムで生成する - 4 - フィールドを扱う

#はじめに
この記事は、SkyrimというゲームソフトのModファイルのバリナリ解析とそれを利用してModを生成するC#のコードについて記載していくシリーズ物です。
ファイルフォーマットについての詳しい情報は以下のサイトがあります。(以降UESP)
[Tes5Mod:Mod File Format - The Unofficial Elder Scrolls Pages (UESP)](http://en.uesp.net/wiki/Tes5Mod:Mod_File_Format)

前回はレコードについて扱いましたので、今回はフィールドについてです。

- グループ
    - レコード
        - <font color=red>フィールド</font>

#フィールドクラス
フィールドのヘッダー構成は次の通りです。

|項目名|型|byte数|byte数合計|説明|
|:--|:--|--:|--:|:--|
|Signature|string|4|4|どのような情報を扱うかを識別する記号。|
|DataSize|ushort|2|6|ヘッダーサイズを含まないフィールドの全体サイズ。|

フィールド内でもデータの内容が分かれていたりしますが、後は、構造体として何byte目が何の情報で・・・のように扱うことになります。

```C#
    public class TesField : TesBase
    {
        public TesString Signature { get; }
        public TesUInt16 DataSize { get; }
        public TesList<ITesBase> Values { get; } = new TesList<ITesBase>();
        public TesField(TesFileReader fr)
        {
            Signature = new TesString(fr.GetString(4));
            DataSize = new TesUInt16(fr);
            Values.Add(fr.GetBytes(DataSize.Value));
            OutputItems.Add(Signature);
            OutputItems.Add(DataSize);
            OutputItems.Add(Values);
        }
    }
```

まずは、そのまま`DataSize`分のバイト数を取り込むようにしていますが、後々個別のフィールドを扱うように、一応リストにしておきます。

では、フィールドを扱うようにレコードクラスなどに修正を入れます。

```C#:TesRecord
    public class TesRecord : TesBase
    {
        public TesHeader Header { get; }
        public Dictionary<string, TesList<TesField>> Fields { get; } = new Dictionary<string, TesList<TesField>>();

        public TesRecord(TesFileReader fr)
        {
            Header = new TesHeader(fr);
            OutputItems.Add(Header);
            while (!fr.EOF)
            {
                TesField field = ReadField(fr) ?? new TesField(fr.GetField());
                AddField(field);
            }
       }
        public void AddField(TesField field)
        {
            OutputItems.Add(field);
            if (!Fields.ContainsKey(field.Signature))
                Fields.Add(field.Signature, new TesList<TesField>());

            Fields[field.Signature].Add(field);
        }
        public virtual TesField ReadField(TesFileReader fr)
        {
            TesField result = null;

            string id = fr.GetTypeID();
            switch (id)
            {
            }
            return result;
        }
    }
```

```C#:TesFileReader
        public TesFileReader GetField(bool next = true)
        {
            long count = GetUInt16(4, false) + 6;
            TesFileReader result = new TesFileReader(br, pos, pos + count);
            if (next)
                pos += count;

            return result;
        }
        public string GetTypeID(long offset = 0)
        {
            string result = GetString(4, offset, false);
            return result;
        }
```

レコードクラスはそこそこ手入れをしました。
まず、フィールドについては、出力用の`OutputItems`に追加すると共に、Signatureでアクセスできるように`Dictionary`に登録することにします。
また、同じSignatureで複数フィールドある場合があるため、リストに追加します。
フィールドの読み取りは、後々レコードクラスを継承して個別のレコードに対応した際に、必要なフィールドを処理できるようにしておきます。
特に、いくつかのフィールドは同じSignatureでも、中身が異なるケースがあるため、注意が必要です。

以上、今回はここまでです。

|前回|次回|
|:--|--:|
|[3 - レコードを扱う](http://qiita.com/rrryutaro/items/4b06dc699934c55e08e5)|[5 - Modファイルを扱う](http://qiita.com/rrryutaro/items/63767542371c343bf192)|