【Unityエディター拡張】ファイルの中身をバイナリで表示するEditorWindowを作ってみた

![image](https://qiita-image-store.s3.amazonaws.com/0/44288/60150800-4515-5468-5241-95453c72934b.png)

Unity上でファイルをバイナリで表示させてみたくなったので作ってみました.

``` BinaryViewer.cs
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;

public class BinaryViewer : EditorWindow
{
  // レイアウト
  private const int WindowSizeX = SliderPosX + 24;
  private const int WindowSizeY = 480;

  private const int SliderSpaceX = 4;
  private const int SliderSpaceY = 12;

  private const int SliderSizeX = 24;
  private const int SliderPosX = BinaryLabelSize + BinaryPosX + BinarySpaceX * Row + 12;

  private const int BinaryLabelSize = 50;
  private const int BinaryPosX = 180;
  private const int BinarySpaceX = 20;
  private const int BinarySpaceY = 22;

  [SerializeField]
  private UnityEngine.Object asset;

  private byte[] bytes;
  private string[] texts;
  private const int Row = 8; // 横一列に並べるバイナリの数

  private float sliderPosition = 0f;
  private float scrollPosition;
  private float scrollMinPosition = 0f;
  private float scrollMaxPosition;
  private float scrollSpeed = 1f; // スクロールの速さ

  private int topIndex = 0;
  private int botIndex = 0;

  [MenuItem("Window/BinaryViewer")]
  static void Open()
  {
    var window = ScriptableObject.CreateInstance<BinaryViewer>();
    window.position = new Rect(new Vector2(20f, 30f), new Vector2(WindowSizeX, WindowSizeY));
    window.Show();
  }

  void OnGUI()
  {
    float SliderMinY = SliderSpaceY;
    float SliderMaxY = this.position.size.y - SliderSpaceY;
    float SliderSizeY = SliderMaxY - SliderMinY;

    if (this.bytes != null)
    {
      this.scrollPosition = Mathf.Lerp(this.scrollMinPosition, this.scrollMaxPosition, (this.sliderPosition - SliderMinY) / SliderSizeY);

      switch (Event.current.type)
      {
        case EventType.ScrollWheel:
          this.sliderPosition += Mathf.Sign(Event.current.delta.y) * BinarySpaceY * this.scrollSpeed;
          Repaint();
          break;
      }
      this.topIndex = Mathf.FloorToInt((this.scrollPosition - this.scrollMinPosition) / BinarySpaceY) * Row;
      this.botIndex = this.topIndex + Mathf.FloorToInt(this.position.size.y / BinarySpaceY - 1) * Row;

      this.topIndex = Mathf.Max(this.topIndex, 0);
      this.botIndex = Mathf.Min(this.botIndex, this.texts.Length);
    }

    bool load = false;
    if (GUI.Button(new Rect(2, 10, 160, 22), "Load"))
    {
      load = true;
    }

    bool clear = false;
    EditorGUI.BeginChangeCheck();
    this.asset = EditorGUI.ObjectField(new Rect(4, 38, 160, 16), this.asset, typeof(UnityEngine.Object), false);
    if (EditorGUI.EndChangeCheck())
    {
      clear = true;
    }

    this.DrawSlider(SliderMinY, SliderMaxY, SliderSizeY);

    this.DrawBinary();

    if (clear)
    {
      this.bytes = null;
      this.texts = null;
    }

    if (load)
    {
      if (this.asset != null)
      {
        this.sliderPosition = SliderMinY;
        this.ReadAsset();
      }
    }
  }

  // スライダー表示
  private void DrawSlider(float SliderMinY, float SliderMaxY, float SliderSizeY)
  {
    sliderPosition = GUI.VerticalSlider(new Rect(SliderPosX, SliderMinY, SliderSizeX, SliderSizeY), sliderPosition, SliderMinY, SliderMaxY);
  }

  // バイナリ表示
  private void DrawBinary()
  {
    if (this.texts != null)
    {
      float x = BinaryPosX + BinaryLabelSize;
      float y = -4;

      for (int i = this.topIndex; i < this.botIndex; i++)
      {
        if (i % Row == 0)
        {
          x = BinaryPosX + BinaryLabelSize;
          y += BinarySpaceY;

          // 行番号
          EditorGUI.LabelField(new Rect(x - BinaryLabelSize, y, BinaryLabelSize, 16), (i / Row).ToString());
        }
        else
        {
          x += BinarySpaceX;
        }

        // バイナリ
        EditorGUI.TextArea(new Rect(x, y, 22, 16), this.texts[i]);
      }

    }
  }

  // アセットを読み込んでバイナリを取得
  private void ReadAsset()
  {
    var split = AssetDatabase.GetAssetPath(this.asset).Split('/');
    var path = Application.dataPath + "/";
    for (int i = 1; i < split.Length - 1; i++)
    {
      path += split[i] + "/";
    }
    path += split[split.Length - 1];

    FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
    BinaryReader bin = new BinaryReader(fileStream);
    this.bytes = bin.ReadBytes((int)bin.BaseStream.Length);

    // byte配列 -> 16進数文字列
    // 参考 http://qiita.com/shusakuorz/items/f90aa57b4ddc2d01e3ea
    this.texts = BitConverter.ToString(this.bytes).Split('-');

    this.scrollMaxPosition = BinarySpaceY * this.bytes.Length / Row;

    Debug.Log(this.bytes.Length + "bytes");
  }
}
```

余力があれば編集機能も実装してバイナリエディタにしたい

#参考
【備忘録】byte配列⇒16進数文字列へ変換
http://qiita.com/shusakuorz/items/f90aa57b4ddc2d01e3ea