using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Toolbox.Library.IO; using Toolbox.Library; using System.Windows.Forms; namespace FirstPlugin { public class XLINK : TreeNodeFile, IFileFormat { public FileType FileType { get; set; } = FileType.Effect; public bool CanSave { get; set; } public string[] Description { get; set; } = new string[] { "Effect Link" }; public string[] Extension { get; set; } = new string[] { "*.bslnk", "*.belnk" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } public bool Identify(System.IO.Stream stream) { using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) { return reader.CheckSignature(4, "XLNK"); } } public Type[] Types { get { List types = new List(); return types.ToArray(); } } public void Load(System.IO.Stream stream) { CanSave = false; Text = FileName; Header Header = new Header(); Header.Read(new FileReader(stream)); var userData = new TreeNode("User Data"); Nodes.Add(userData); var hashes = new TreeNode("Hashes"); userData.Nodes.Add(hashes); foreach (var hash in Header.UserDataTable.CRC32Hashes) hashes.Nodes.Add(new TreeNode(hash.ToString("x"))); var paramDefines = new TreeNode("Param Defines"); Nodes.Add(paramDefines); foreach (var param in Header.ParamDefineTable.UserParams) paramDefines.Nodes.Add(param.Name); foreach (var param in Header.ParamDefineTable.TriggerParams) paramDefines.Nodes.Add(param.Name); foreach (var param in Header.ParamDefineTable.UserParams) paramDefines.Nodes.Add(param.Name); } public void Unload() { } public void Save(System.IO.Stream stream) { } //Documentation from https://github.com/Kinnay/Nintendo-File-Formats/wiki/XLINK-File-Format#header public class Header { public ushort ByteOrderMark; public UserDataTable UserDataTable; public ParamDefineTable ParamDefineTable; public void Read(FileReader reader) { reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian; reader.ReadSignature(4, "XLNK"); uint FileSize = reader.ReadUInt32(); uint Version = reader.ReadUInt32(); uint numResParam = reader.ReadUInt32(); uint numResAssetParam = reader.ReadUInt32(); uint numResTriggerOverwriteParam = reader.ReadUInt32(); uint triggerOverwriteParamTablePos = reader.ReadUInt32(); uint localPropertyNameRefTablePos = reader.ReadUInt32(); uint numLocalPropertyNameRefTable = reader.ReadUInt32(); uint numLocalPropertyEnumNameRefTable = reader.ReadUInt32(); uint numDirectValueTable = reader.ReadUInt32(); uint numRandomTable = reader.ReadUInt32(); uint numCurveTable = reader.ReadUInt32(); uint numCurvePointTable = reader.ReadUInt32(); uint exRegionPos = reader.ReadUInt32(); uint numUser = reader.ReadUInt32(); uint conditionTablePos = reader.ReadUInt32(); uint nameTablePos = reader.ReadUInt32(); UserDataTable = new UserDataTable(); UserDataTable.Read(reader, (int)numUser); ParamDefineTable = new ParamDefineTable(); ParamDefineTable.Read(reader); } } public class UserDataTable { public uint[] CRC32Hashes; public uint[] ExRegionOffsets; public void Read(FileReader reader, int EntryCount) { CRC32Hashes = reader.ReadUInt32s(EntryCount); ExRegionOffsets = reader.ReadUInt32s(EntryCount); } } public class ParamDefineTable { public List UserParams = new List(); public List AssetParams = new List(); public List TriggerParams = new List(); public void Read(FileReader reader) { uint SectionSize = reader.ReadUInt32(); uint numUserParams = reader.ReadUInt32(); uint numAssetParams = reader.ReadUInt32(); uint unknown = reader.ReadUInt32(); uint numTriggerParams = reader.ReadUInt32(); for (int i = 0; i < numUserParams; i++) { var entry = new ParamDefineEntry(); entry.Read(reader); UserParams.Add(entry); } for (int i = 0; i < numAssetParams; i++) { var entry = new ParamDefineEntry(); entry.Read(reader); AssetParams.Add(entry); } for (int i = 0; i < numTriggerParams; i++) { var entry = new ParamDefineEntry(); entry.Read(reader); TriggerParams.Add(entry); } List StringTable = new List(); long StringTablePosition = reader.Position; foreach (var param in UserParams) param.ReadString(reader, StringTablePosition); foreach (var param in AssetParams) param.ReadString(reader, StringTablePosition); foreach (var param in TriggerParams) param.ReadString(reader, StringTablePosition); } } public class ParamDefineEntry { internal uint NamePos; public string Name { get; set; } public uint Type { get; set; } public byte[] DefaultValue { get; set; } public void Read(FileReader reader) { NamePos = reader.ReadUInt32(); //Offset from string table Type = reader.ReadUInt32(); DefaultValue = reader.ReadBytes(4); } public void ReadString(FileReader reader, long TablePosition) { Console.WriteLine("NamePos " + NamePos); reader.Position = TablePosition + NamePos; Name = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated); Console.WriteLine("Name " + Name); } } } }