pkNX/pkNX.Structures/Scripts/AmxHeader.cs
2022-10-01 17:46:11 -07:00

272 lines
6.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace pkNX.Structures;
[StructLayout(LayoutKind.Sequential)]
public class AmxHeader
{
// Cell Size magic verification
public const ushort MAGIC_32 = 0xf1e0;
public const ushort MAGIC_64 = 0xf1e1;
public const ushort MAGIC_16 = 0xf1e2;
/// <summary> Size of the "file" </summary>
public int Size; // 0x00
/// <summary> Signature </summary>
public ushort Magic; // 0x04
/// <summary> File format version </summary>
public byte FileVersion; // 0x06
/// <summary> Required version of the AMX </summary>
public byte AMXVersion; // 0x07
/// <summary> Feature flags </summary>
public AmxFlags Flags; // 0x08
/// <summary> Size of a definition record </summary>
public short DefinitionSize; // 0x0A
/// <summary> Initial value of COD - code block </summary>
public int COD; // 0x0C
/// <summary> initial value of DAT - data block </summary>
public int Data; // 0x10
/// <summary> Initial value of HEA - start of the heap </summary>
public int Heap; // 0x14
/// <summary> Initial value of STP - stack top </summary>
public int StackTop; // 0x18
/// <summary> Initial value of CIP - the instruction pointer </summary>
public int CurrentInstructionPointer; // 0x20
/// <summary> Offset to the "public functions" table </summary>
public int Publics; // 0x24
/// <summary> Offset to the "native functions" table </summary>
public int Natives; // 0x28
/// <summary> Offset to the table of libraries </summary>
public int Libraries; // 0x2C
/// <summary> Offset to the "public variables" table </summary>
public int PublicVars; // 0x30
/// <summary> Offset to the "public tagnames" table </summary>
public int Tags; // 0x34
/// <summary> Offset to the name table </summary>
public int NameTable; // 0x38
/// <summary> Offset to the overlay table </summary>
public int Overlays; // 0x3C
public int CellSize
{
get
{
return Magic switch
{
MAGIC_16 => 16,
MAGIC_32 => 32,
MAGIC_64 => 64,
_ => throw new ArgumentException("Invalid Magic identifier."),
};
}
}
}
/* File format version
* 0 original version
* 1 opcodes JUMP.pri, SWITCH and CASETBL
* 2 compressed files
* 3 public variables
* 4 opcodes SWAP.pri/alt and PUSHADDR
* 5 tagnames table
* 6 reformatted header
* 7 name table, opcodes SYMTAG & SYSREQ.D
* 8 opcode BREAK, renewed debug interface
* 9 macro opcodes
* 10 position-independent code, overlays, packed instructions
* 11 relocating instructions for the native interface, reorganized instruction set
*/
/// <summary>
/// Debug data at the end of an amx
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public class AmxDebugHeader
{
public const ushort MAGIC_DEBUG = 0xf1ef;
public int Size;
public ushort Magic;
public byte FileVersion;
public byte AMXVersion;
public AmxFlags Flags;
public short Files;
public short Lines;
public short Symbols;
public short Tags;
public short Automatons;
public short States;
public const int SIZE = 36;
}
public class TableRecord
{
public TableRecord(string name, uint address)
{
Name = name;
Address = address;
}
public string Name { get; }
public uint Address { get; }
}
public class Tag
{
public Tag(string name, uint tagID)
{
TagID = tagID;
Name = name;
}
public uint TagID { get; }
public string Name { get; }
}
public class Dimension
{
public Dimension(int tagID, Tag tag, int size)
{
TagID = tagID;
Tag = tag;
Size = size;
}
public int TagID { get; }
public Tag Tag { get; }
public int Size { get; }
}
public class Argument
{
public Argument(VariableType type, string name, int tagID, Tag tag, Dimension[] dims)
{
Type = type;
Name = name;
TagID = tagID;
Tag = tag;
Dimensions = dims;
}
public int TagID { get; }
public VariableType Type { get; }
public string Name { get; }
public Tag Tag { get; }
public Dimension[] Dimensions { get; }
}
public enum Register : uint
{
Pri,
Alt,
}
public enum Scope : uint
{
Global,
Local,
Static,
}
public class Variable
{
public Variable(int addr, int tagID, Tag tag, uint codeStart,
uint codeEnd, VariableType type, Scope scope,
string name, Dimension[] dims = null)
{
Address = addr;
TagID = (uint)tagID;
Tag = tag;
CodeStart = codeStart;
CodeEnd = codeEnd;
Type = type;
Scope = scope;
Name = name;
Dims = dims;
}
public int Address { get; }
public uint CodeStart { get; }
public uint CodeEnd { get; }
public string Name { get; }
public VariableType Type { get; }
public Scope Scope { get; }
public Tag Tag { get; set; }
public uint TagID { get; }
public Dimension[] Dims { get; }
}
public class Signature
{
public Signature(string name) => Name = name;
public Tag ReturnType { get; set; }
public uint TagID { get; protected set; }
public string Name { get; }
public Argument[] Args { get; protected set; }
}
public class Native : Signature
{
public Native(string name, int index) : base(name) => Index = index;
public int Index { get; }
public void SetDebugInfo(int tagID, Tag tag, Argument[] args)
{
TagID = (uint)tagID;
ReturnType = tag;
Args = args;
}
}
public class Function : Signature
{
public Function(uint addr, uint codeStart, uint codeEnd, string name, Tag tag)
: base(name)
{
Address = addr;
CodeStart = codeStart;
CodeEnd = codeEnd;
ReturnType = tag;
}
public Function(uint addr, uint codeStart, uint codeEnd, string name, uint tagID)
: base(name)
{
Address = addr;
CodeStart = codeStart;
CodeEnd = codeEnd;
TagID = tagID;
}
public void SetArguments(List<Argument> from) => Args = from.ToArray();
public uint Address { get; }
public uint CodeStart { get; }
public uint CodeEnd { get; }
public bool Within(uint pc) => pc >= CodeStart && pc < CodeEnd;
}