/* vim: ts=4 sw=4 sts=4 fenc=utf-8 :
 * =============================================================================
 *  Windows 実行ファイル PEフォーマット
 * =============================================================================
 */
/**
 * 次の資料を元に作成しています.$(BR)
 * 「Microsoft Platform SDK」 のヘッダファイル$(BR)
 * 「PECOFF仕様」
 *  $(LINK http://www.microsoft.com/whdc/system/platform/firmware/PECOFFeula.mspx)
 * (2008/07/28 版)$(BR)
 * 日本語資料が欲しい...
 * $(BR)$(BR)
 *
 * $(TABLE
 * $(TR $(TD IMAGE_DOS_HEADER  ) $(TD MS-DOS用ヘッダ                        ))
 * $(TR $(TD Stab Program      ) $(TD MS-DOSでの実行時用プログラム          ))
 * $(TR $(TD PE Header         ) $(TD PEイメージファイルヘッダ              ))
 * $(TR $(TD PE Optional Header) $(TD PEイメージファイルオプションヘッダ    ))
 * $(TR $(TD Data Dicationary  ) $(TD データディクショナリ                  ))
 * $(TR $(TD Section Data      ) $(TD セクションデータ                      ))
 * $(TR $(TD COFF Line Number  ) $(TD COFF行番号                            ))
 * $(TR $(TD COFF Symbols      ) $(TD COFF行シンボル                        ))
 * $(TR $(TD COFF Debug        ) $(TD COFFデバッグ情報                      ))
 * )
 */
module sal.io.format.fmt_pe;

public import sal.io.format.fmt;

version (BigEndian)
{
    invariant
    {
        // シグネチャー定義
        ushort  IMAGE_DOS_SIGNATURE     = 0x4D5A;       /// MZ
        uint    IMAGE_NT_SIGNATURE      = 0x50450000;   /// PE\0\0
    }
}
else
{
    invariant
    {
        // シグネチャー定義
        ushort  IMAGE_DOS_SIGNATURE     = 0x5A4D;       /// MZ
        uint    IMAGE_NT_SIGNATURE      = 0x00004550;   /// PE\0\0
    }
}

// MAGIC 定義
ushort IMAGE_NT_OPTIONAL_HDR32_MAGIC    = 0x10b;
ushort IMAGE_NT_OPTIONAL_HDR64_MAGIC    = 0x20b;
ushort IMAGE_ROM_OPTIONAL_HDR_MAGIC     = 0x107;


/**
 * Machine for IMAGE_FILE_HEADER.
 */
enum IMAGE_FILE_MACHINE : ushort
{
    UNKNOWN     = 0,
    I386        = 0x014c,   /// Intel 386.
    R3000       = 0x0162,   /// MIPS little-endian, 0x160 big-endian
    R4000       = 0x0166,   /// MIPS little-endian
    R10000      = 0x0168,   /// MIPS little-endian
    WCEMIPSV2   = 0x0169,   /// MIPS little-endian WCE v2
    ALPHA       = 0x0184,   /// Alpha_AXP
    SH3         = 0x01a2,   /// SH3 little-endian
    SH3DSP      = 0x01a3,
    SH3E        = 0x01a4,   /// SH3E little-endian
    SH4         = 0x01a6,   /// SH4 little-endian
    SH5         = 0x01a8,   /// SH5
    ARM         = 0x01c0,   /// ARM Little-Endian
    THUMB       = 0x01c2,
    AM33        = 0x01d3,
    POWERPC     = 0x01F0,   /// IBM PowerPC Little-Endian
    POWERPCFP   = 0x01f1,
    IA64        = 0x0200,   /// Intel 64
    MIPS16      = 0x0266,   /// MIPS
    ALPHA64     = 0x0284,   /// ALPHA64
    MIPSFPU     = 0x0366,   /// MIPS
    MIPSFPU16   = 0x0466,   /// MIPS
    AXP64       = ALPHA64,  /// same ALPHA64
    TRICORE     = 0x0520,   /// Infineon
    CEF         = 0x0CEF,
    EBC         = 0x0EBC,   /// EFI Byte Code
    AMD64       = 0x8664,   /// AMD64 (K8)
    M32R        = 0x9041,   /// M32R little-endian
    CEE         = 0xC0EE
}


invariant
{
    // 定数
    int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;	/// ディレクトリエントリ
    int IMAGE_SIZEOF_SHORT_NAME          = 8;	/// セクション名の長さ

	// -------------------------------------------------------------------------
    // ファイル属性値
	// -------------------------------------------------------------------------
    ushort IMAGE_FILE_RELOCS_STRIPPED          = 0x0001;  /// ファイルから再配置情報削除済
    ushort IMAGE_FILE_EXECUTABLE_IMAGE         = 0x0002;  /// 実行可能ファイル
    ushort IMAGE_FILE_LINE_NUMS_STRIPPED       = 0x0004;  /// [非推奨] COFF行番号削除済
    ushort IMAGE_FILE_LOCAL_SYMS_STRIPPED      = 0x0008;  /// [非推奨] COFFシンボル削除済
    ushort IMAGE_FILE_AGGRESIVE_WS_TRIM        = 0x0010;  /// [非推奨] 旧版 working set 削除済
    ushort IMAGE_FILE_LARGE_ADDRESS_AWARE      = 0x0020;  /// 2GBアドレス以上のハンドル可
    ushort IMAGE_FILE_BYTES_REVERSED_LO        = 0x0080;  /// [非推奨] リトルエンディアン
    ushort IMAGE_FILE_32BIT_MACHINE            = 0x0100;  /// 32bit-wordアーキテクチャ
    ushort IMAGE_FILE_DEBUG_STRIPPED           = 0x0200;  /// デバッグ情報削除済
    ushort IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP  = 0x0400;  /// メディア上のイメージ,スワップより実行
    ushort IMAGE_FILE_NET_RUN_FROM_SWAP        = 0x0800;  /// ネット上のイメージ,スワップより実行
    ushort IMAGE_FILE_SYSTEM                   = 0x1000;  /// システムファイル
    ushort IMAGE_FILE_DLL                      = 0x2000;  /// DLL
    ushort IMAGE_FILE_UP_SYSTEM_ONLY           = 0x4000;  /// ユニプロセッサ上でのみ実行すべき
    ushort IMAGE_FILE_BYTES_REVERSED_HI        = 0x8000;  /// [非推奨] ビッグエンディアン

	// -------------------------------------------------------------------------
    // DllCharacteristics エントリ
	// -------------------------------------------------------------------------
//  ushort IMAGE_LIBRARY_PROCESS_INIT            = 0x0001;  /// 予約
//  ushort IMAGE_LIBRARY_PROCESS_TERM            = 0x0002;  /// 予約
//  ushort IMAGE_LIBRARY_THREAD_INIT             = 0x0004;  /// 予約
//  ushort IMAGE_LIBRARY_THREAD_TERM             = 0x0008;  /// 予約
    ushort IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200;  /// isolationを認識するがimageを分離しない
    ushort IMAGE_DLLCHARACTERISTICS_NO_SEH       = 0x0400;  /// SEHを使用しない. SEハンドラは、存在しないかもしれない
    ushort IMAGE_DLLCHARACTERISTICS_NO_BIND      = 0x0800;  /// バインドしない
//                                                 0x1000;  /// 予約
    ushort IMAGE_DLLCHARACTERISTICS_WDM_DRIVER   = 0x2000;  /// ドライバがWDMモデルを使用する
//                                                 0x4000;  /// 予約
    ushort IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;

	// -------------------------------------------------------------------------
	//  セクション特性
	// -------------------------------------------------------------------------
//  uint IMAGE_SCN_TYPE_REG                 = 0x00000000;   /// 予約
//  uint IMAGE_SCN_TYPE_DSECT               = 0x00000001;   /// 予約
//  uint IMAGE_SCN_TYPE_NOLOAD              = 0x00000002;   /// 予約
//  uint IMAGE_SCN_TYPE_GROUP               = 0x00000004;   /// 予約
	uint IMAGE_SCN_TYPE_NO_PAD              = 0x00000008;   /// 予約
//  uint IMAGE_SCN_TYPE_COPY                = 0x00000010;   /// 予約
	uint IMAGE_SCN_CNT_CODE					= 0x00000020;	/// 実行コードを含むセクション
	uint IMAGE_SCN_CNT_INITIALIZED_DATA		= 0x00000040;   /// 初期化データを含むセクション
	uint IMAGE_SCN_CNT_UNINITIALIZED_DATA	= 0x00000080;   /// 未初期化データを含むセクション
	uint IMAGE_SCN_LNK_OTHER                = 0x00000100;   /// 予約
	uint IMAGE_SCN_LNK_INFO                 = 0x00000200;   /// コメント、他情報を含むセクション
//  uint IMAGE_SCN_TYPE_OVER                = 0x00000400;  	/// 予約
	uint IMAGE_SCN_LNK_REMOVE               = 0x00000800;   /// イメージの一部でないものを含む
	uint IMAGE_SCN_LNK_COMDAT               = 0x00001000;   /// comdat を含むセクション
//                                            0x00002000;   /// 予約
//  uint IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000;
	uint IMAGE_SCN_NO_DEFER_SPEC_EXC        = 0x00004000;
	uint IMAGE_SCN_GPREL                    = 0x00008000;
	uint IMAGE_SCN_MEM_FARDATA              = 0x00008000;
//  uint IMAGE_SCN_MEM_SYSHEAP - Obsolete     0x00010000;
	uint IMAGE_SCN_MEM_PURGEABLE            = 0x00020000;
	uint IMAGE_SCN_MEM_16BIT                = 0x00020000;
	uint IMAGE_SCN_MEM_LOCKED               = 0x00040000;
	uint IMAGE_SCN_MEM_PRELOAD              = 0x00080000;
	uint IMAGE_SCN_ALIGN_1BYTES             = 0x00100000;
	uint IMAGE_SCN_ALIGN_2BYTES             = 0x00200000;
	uint IMAGE_SCN_ALIGN_4BYTES             = 0x00300000;
	uint IMAGE_SCN_ALIGN_8BYTES             = 0x00400000;
	uint IMAGE_SCN_ALIGN_16BYTES            = 0x00500000;
	uint IMAGE_SCN_ALIGN_32BYTES            = 0x00600000;
	uint IMAGE_SCN_ALIGN_64BYTES            = 0x00700000;
	uint IMAGE_SCN_ALIGN_128BYTES           = 0x00800000;
	uint IMAGE_SCN_ALIGN_256BYTES           = 0x00900000;
	uint IMAGE_SCN_ALIGN_512BYTES           = 0x00A00000;
	uint IMAGE_SCN_ALIGN_1024BYTES          = 0x00B00000;
	uint IMAGE_SCN_ALIGN_2048BYTES          = 0x00C00000;
	uint IMAGE_SCN_ALIGN_4096BYTES          = 0x00D00000;
	uint IMAGE_SCN_ALIGN_8192BYTES          = 0x00E00000;
// Unused                                     0x00F00000;
	uint IMAGE_SCN_ALIGN_MASK               = 0x00F00000;
	uint IMAGE_SCN_LNK_NRELOC_OVFL          = 0x01000000;  /// extended 再配置を含むセクション
	uint IMAGE_SCN_MEM_DISCARDABLE          = 0x02000000;  /// 破棄可能なセクション
	uint IMAGE_SCN_MEM_NOT_CACHED           = 0x04000000;  /// キャッシュ不可なセクション
	uint IMAGE_SCN_MEM_NOT_PAGED            = 0x08000000;  /// ページ不可なセクション
	uint IMAGE_SCN_MEM_SHARED               = 0x10000000;  /// 共有不可なセクション
	uint IMAGE_SCN_MEM_EXECUTE              = 0x20000000;  /// 実行可能なセクション
	uint IMAGE_SCN_MEM_READ                 = 0x40000000;  /// 読み取り可能なセクション
	uint IMAGE_SCN_MEM_WRITE                = 0x80000000;  /// 書き込み可能なセクション
	uint IMAGE_SCN_SCALE_INDEX              = 0x00000001;  /// TLSのインデックススケーリング
}


/**
 * サブシステム.
 */
enum IMAGE_SUBSYSTEM : ushort
{
    UNKNOWN                 = 0,    /// 不明.
    NATIVE                  = 1,    /// デバイスドライバ, Native プロセス用
    WINDOWS_GUI             = 2,    /// GUIサブシステム
    WINDOWS_CUI             = 3,    /// CUIサブシステム
    OS2_CUI                 = 5,    /// OS/2 CUI サブシステム
    POSIX_CUI               = 7,    /// POSIX CUI サブシステム
    NATIVE_WINDOWS          = 8,    /// Native Windows 9x ドライバ
    WINDOWS_CE_GUI          = 9,    /// Windows CEサブシステム
    EFI_APPLICATION         = 10,   ///
    EFI_BOOT_SERVICE_DRIVER = 11,   ///
    EFI_RUNTIME_DRIVER      = 12,   ///
    EFI_ROM                 = 13,   ///
    XBOX                    = 14    ///
}




// =============================================================================
//  以下、構造体
// =============================================================================

/**
 * DOS .EXE ヘッダ.
 */
struct IMAGE_DOS_HEADER
{
    ushort      e_magic;        /// Magic "MZ" 固定
    ushort      e_cblp;         /// ファイルの最終ページバイト数
    ushort      e_cp;           /// ファイルのページ数
    ushort      e_crlc;         /// 再配置
    ushort      e_cparhdr;      /// パラグラフ中のヘッダサイズ
    ushort      e_minalloc;     /// エキストラパラグラフに必要な最小値
    ushort      e_maxalloc;     /// エキストラパラグラフに必要な最大値
    ushort      e_ss;           /// 初期SS(スタックセグメント)
    ushort      e_sp;           /// 初期SP(スタックポインタ)
    ushort      e_csum;         /// チェックサム
    ushort      e_ip;           /// 初期IP(インストラクションポインタ)
    ushort      e_cs;           /// 初期CS(コードセグメント)
    ushort      e_lfarlc;       /// 再配置テーブルのファイルアドレス
    ushort      e_ovno;         /// オーバレイ番号
    ushort[4]   e_res;          /// 予約
    ushort      e_oemid;        /// OEM ID
    ushort      e_oeminfo;      /// OEM 情報
    ushort[10]  e_res2;         /// 予約
    uint        e_lfanew;       /// PEヘッダが格納されている位置
}


/**
 * PEヘッダ.
 */
struct IMAGE_NT_HEADERS32
{
    uint                    Signature;      /// "PE\0\0" 固定
    IMAGE_FILE_HEADER       FileHeader;     /// PEヘッダ情報
    IMAGE_OPTIONAL_HEADER32 OptionalHeader; /// オプショナルヘッダ
}


/**
 * ファイルヘッダ.
 */
struct IMAGE_FILE_HEADER
{
    IMAGE_FILE_MACHINE  Machine;                /// see IMAG_FILE_MACHINE
    ushort              NumberOfSections;       /// セクション数
    uint                TimeDateStamp;          /// EXE作成日
    uint                PointerToSymbolTable;   /// シンボルテーブル位置(EXEでは0)
    uint                NumberOfSymbols;        /// シンボル数(EXEでは0)
    ushort              SizeOfOptionalHeader;   /// オプションヘッダサイズ
    ushort              Characteristics;        /// ファイル属性
}


/**
 * IMAGE_DATA_DIRECTORY.
 */
struct IMAGE_DATA_DIRECTORY
{
    uint    VirtualAddress;     /// 仮想アドレス
    uint    Size;               /// サイズ
}


/**
 * オプショナルヘッダ.
 */
struct IMAGE_OPTIONAL_HEADER32 {
    //
    // Standard fields.
    //
    ushort  Magic;                      /// Magic
    ubyte   MajorLinkerVersion;         /// リンカメジャーバージョン
    ubyte   MinorLinkerVersion;         /// リンカマイナーバージョン
    uint    SizeOfCode;                 /// コードセクションのサイズ
    uint    SizeOfInitializedData;      /// 初期化されたデータセクションサイズ
    uint    SizeOfUninitializedData;    /// 未初期化データセクションサイズ
    uint    AddressOfEntryPoint;        /// エントリポイント [ImageBase]
    uint    BaseOfCode;                 /// メモリにロード後のコードセクション位置
    uint    BaseOfData;                 /// メモリにロード後のデータセクション位置


    //
    // NT additional fields.
    //

    /**
     * メモリ上のどこに、EXEファイルイメージをロードするかの位置.
     * $(BR)$(BR)
     * 0x00400000 通常のEXEファイル$(BR)
     * 0x10000000 DLLファイル$(BR)
     * 0x00010000 WindowsCEのEXEファイル$(BR)
     */
    uint    ImageBase;

    /**
     * 各セクションがメモリにロードされるときの境界をバイト単位で指定.
     */
    uint    SectionAlignment;

    /**
     * ファイル上のアライメントを指定.
     */
    uint    FileAlignment;

    ushort  MajorOperatingSystemVersion;    /// OS Major Version (多くの場合4)
    ushort  MinorOperatingSystemVersion;    /// OS Minor Versoin (多くの場合0)
    ushort  MajorImageVersion;              /// EXE Major Version (動作には影響無し)
    ushort  MinorImageVersion;              /// EXE Minor Version (動作には影響無し)
    ushort  MajorSubsystemVersion;          /// Subsystem Major Version (OSと一緒でよい)
    ushort  MinorSubsystemVersion;          /// Subsystem Minor Version (OSと一緒でよい)
    uint    Win32VersionValue;              /// 予約 (0でなければならない)
    uint    SizeOfImage;                    /// メモリ上にロードした際のイメージサイズ
    uint    SizeOfHeaders;                  /// ヘッダ情報総バイト数
    uint    CheckSum;                       /// チェックサム(EXEの場合は0で良い、参照:imagehelp.dll)
    IMAGE_SUBSYSTEM Subsystem;              /// サブシステム
    ushort  DllCharacteristics;             /// DLLの特性(0でも問題はない)
    uint    SizeOfStackReserve;             /// スタックサイズ
    uint    SizeOfStackCommit;              /// コミットするスタックサイズ
    uint    SizeOfHeapReserve;              /// ローカルヒープサイズ
    uint    SizeOfHeapCommit;               /// コミットするローカルヒープサイズ
    uint    LoaderFlags;                    /// 予約(0でなければならない)
    uint    NumberOfRvaAndSizes;            /// データディクショナリエントリ数(通常16)

    /**
     * 次の16個の要素からなる.
     * $(TABLE
     * $(TR $(TD Export Table           ))
     * $(TR $(TD Import Table           ))
     * $(TR $(TD Resource Table         ))
     * $(TR $(TD Exception Table        ))
     * $(TR $(TD Certificate Table      ))
     * $(TR $(TD Base Relocation Table  ))
     * $(TR $(TD Debug                  ))
     * $(TR $(TD Architecture           ))
     * $(TR $(TD Global Ptr             ))
     * $(TR $(TD TLS Table              ))
     * $(TR $(TD Load Config Table      ))
     * $(TR $(TD Bound Import           ))
     * $(TR $(TD IAT                    ))
     * $(TR $(TD Delay Import Descriptor))
     * $(TR $(TD Reserved               ))
     * )
     */
    IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] DataDirectory;
}


/**
 * セクションヘッダ.
 */
struct IMAGE_SECTION_HEADER {

	/**
	 * セクション名.
	 * 一般的に以下のセクションがある.
	 * $(TABLE
	 * $(TR $(TD .text) $(TD ネイティブコード))
	 * $(TR $(TD .data) $(TD グローバル変数領域、初期値))
	 * $(TR $(TD .idata) $(TD インポート関数情報))
	 * $(TR $(TD .edata) $(TD エクスポート関数情報))
	 * $(TR $(TD .rsrc) $(TD リソース情報))
	 * $(TR $(TD .debug) $(TD デバッグ情報))
	 * $(TR $(TD .reloc) $(TD 再配置情報))
	 * $(TR $(TD .tls) $(TD スレッドごとの静的変数に関する情報))
	 * )
	 */
    ubyte[IMAGE_SIZEOF_SHORT_NAME] Name;

    //union Misc {
    //        uint   PhysicalAddress;
    		uint   VirtualSize;		/// メモリ上セクションサイズ
    //}
    //Misc misc;

    uint	VirtualAddress;			/// メモリ上のセクション位置
    uint	SizeOfRawData;			/// ファイル上のセクションサイズ
    uint	PointerToRawData;		/// ファイル上のセクション位置
    uint	PointerToRelocations;	/// 再配置エントリ情報ファイル上の位置(EXEの場合0)
    uint	PointerToLinenumbers;	/// 行番号エントリ情報ファイル上の位置
    ushort	NumberOfRelocations;	/// 再配置エントリ数(EXEの場合0)
    ushort	NumberOfLinenumbers;	/// 行番号エントリ数
    uint	Characteristics;		/// セクションの特性
}


// -----------------------------------------------------------------------------
//  各セクションヘッダ
// -----------------------------------------------------------------------------
// export
// import
// resource
// exception
// security
// basereloc
// debug
// architecture
// globalptr
// tls
// load config
// bound import
// iat
// delay import
// com descriptor

struct IMAGE_EXPORT_DIRECTORY
{
    uint	Characteristics;		/// 予約 (must be 0)
    uint	TimeDateStamp;			/// タイムスタンプ
    ushort	MajorVersion;			/// Major Version
    ushort	MinorVersion;			/// Minor Version
    uint	Name;					/// 名前
    uint	Base;					/// Ordinal Base
    uint	NumberOfFunctions;		/// アドレステーブル
    uint	NumberOfNames;			/// 名前数
    uint	AddressOfFunctions;     // RVA from base of image
    uint	AddressOfNames;         // RVA from base of image
	uint	AddressOfNameOrdinals;  // RVA from base of image
}



