public MintScript(string name, byte[] version) { XData = new XData(Endianness.Little, new byte[] { 2, 0 }); Version = version; Name = name; SData = new List <byte>(); XRef = new List <byte[]>(); Classes = new List <MintClass>(); }
public MintScript(EndianBinaryReader reader, byte[] version) { XData = new XData(reader); Version = version; uint nameOffs = reader.ReadUInt32(); if (version[0] >= 7) { Hash = reader.ReadBytes(4); } else { Hash = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF } }; uint sdataOffs = reader.ReadUInt32(); uint xrefOffs = reader.ReadUInt32(); uint classOffs = reader.ReadUInt32(); reader.BaseStream.Seek(nameOffs, SeekOrigin.Begin); Name = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadInt32())); reader.BaseStream.Seek(sdataOffs, SeekOrigin.Begin); SData = new List <byte>(); SData.AddRange(reader.ReadBytes(reader.ReadInt32())); reader.BaseStream.Seek(xrefOffs, SeekOrigin.Begin); uint xrefCount = reader.ReadUInt32(); XRef = new List <byte[]>(); for (int i = 0; i < xrefCount; i++) { XRef.Add(reader.ReadBytes(4)); } reader.BaseStream.Seek(classOffs, SeekOrigin.Begin); uint classCount = reader.ReadUInt32(); Classes = new List <MintClass>(); for (int i = 0; i < classCount; i++) { reader.BaseStream.Seek(classOffs + 4 + (i * 4), SeekOrigin.Begin); reader.BaseStream.Seek(reader.ReadUInt32(), SeekOrigin.Begin); Classes.Add(new MintClass(reader, this)); } }
public void Read(EndianBinaryReader reader) { XData = new XData(reader); if (!XData.isValid()) { return; } Version = reader.ReadBytes(4); int namespaceCount = reader.ReadInt32() - 1; reader.BaseStream.Seek(4, SeekOrigin.Current); int scriptCount = reader.ReadInt32(); uint scriptList = reader.ReadUInt32(); uint unk = reader.ReadUInt32(); reader.BaseStream.Seek(0x30, SeekOrigin.Begin); RootNamespaces = reader.ReadUInt32(); Console.WriteLine($"Archive Header Data:" + $"\n-XData-" + $"\nMagic: {XData.Magic}" + $"\nEndianness: {XData.Endianness}" + $"\nFilesize: 0x{XData.Filesize:X8}" + $"\n-Mint Archive-" + $"\nVersion: {string.Join(".", Version)}" + $"\nNamespaces: {namespaceCount}" + $"\nRoot Namespaces: {RootNamespaces}" + $"\nScripts: {scriptCount}" + $"\nScript List Offset: 0x{scriptList:X8}" + $"\nIndex Table Offset: 0x{0x34 + (namespaceCount * 0x14):X8}"); Console.WriteLine("Reading Namespaces..."); Namespaces = new List <Namespace>(); for (int i = 0; i < namespaceCount; i++) { reader.BaseStream.Seek(0x34 + (i * 0x14), SeekOrigin.Begin); uint indexOffset = reader.ReadUInt32(); uint nameOffset = reader.ReadUInt32(); int scrCount = reader.ReadInt32(); int totalScripts = reader.ReadInt32(); int childrenCount = reader.ReadInt32(); reader.BaseStream.Seek(indexOffset, SeekOrigin.Begin); int index = reader.ReadInt32(); reader.BaseStream.Seek(nameOffset, SeekOrigin.Begin); string name = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadInt32())); Namespaces.Add(new Namespace(index, name, scrCount, totalScripts, childrenCount)); } Console.WriteLine("Reading index table..."); IndexTable = new List <int>(); reader.BaseStream.Seek(0x34 + (namespaceCount * 0x14), SeekOrigin.Begin); while (reader.BaseStream.Position < scriptList) { IndexTable.Add(reader.ReadInt32()); } //Console.WriteLine(string.Join(",", IndexTable)); Console.WriteLine("Reading scripts..."); Scripts = new Dictionary <string, MintScript>(); reader.BaseStream.Seek(scriptList, SeekOrigin.Begin); for (int i = 0; i < scriptCount; i++) { reader.BaseStream.Seek(scriptList + (i * 8), SeekOrigin.Begin); uint nameOffset = reader.ReadUInt32(); uint scriptOffset = reader.ReadUInt32(); reader.BaseStream.Seek(nameOffset, SeekOrigin.Begin); string name = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadInt32())); reader.BaseStream.Seek(scriptOffset, SeekOrigin.Begin); XData scrX = new XData(reader); reader.BaseStream.Seek(scriptOffset, SeekOrigin.Begin); using (MemoryStream scr = new MemoryStream(reader.ReadBytes((int)scrX.Filesize))) using (EndianBinaryReader scrReader = new EndianBinaryReader(scr)) Scripts.Add(name, new MintScript(new EndianBinaryReader(scr), Version)); } reader.BaseStream.Seek(unk, SeekOrigin.Begin); //Console.WriteLine(reader.ReadUInt32()); }
public void Write(EndianBinaryWriter writer) { XData.Write(writer); writer.Write(Version); writer.Write(Namespaces.Count + 1); writer.Write(0x24); writer.Write(Scripts.Count); uint scrListOffs = (uint)(0x34 + (Namespaces.Count * 0x14) + (IndexTable.Count * 4)); writer.Write(scrListOffs); //Script data end bound offset, -1 for now until we get there writer.Write(-1); writer.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); //Namespace information writer.Write(RootNamespaces); for (int i = 0; i < Namespaces.Count; i++) { //Console.WriteLine($"{Namespaces[i].Name} - Index {Namespaces[i].Index}, In table: {IndexTable.Contains(Namespaces[i].Index)}, Index: {IndexTable.IndexOf(Namespaces[i].Index)}"); if (!IndexTable.Contains(Namespaces[i].Index)) { writer.Write(scrListOffs); } else { writer.Write((uint)(0x34 + (Namespaces.Count * 0x14) + (IndexTable.IndexOf(Namespaces[i].Index) * 4))); } writer.Write(-1); //Come back to this later for string writing writer.Write(Namespaces[i].Scripts); writer.Write(Namespaces[i].TotalScripts); writer.Write(Namespaces[i].ChildNamespaces); } //writer.Write(scrListOffs); for (int i = 0; i < IndexTable.Count; i++) { writer.Write(IndexTable[i]); } writer.BaseStream.Seek(scrListOffs, SeekOrigin.Begin); for (int i = 0; i < Scripts.Count; i++) { writer.Write(-1); //Come back to this later for string writing writer.Write(-1); } for (int i = 0; i < Scripts.Count; i++) { writer.BaseStream.Seek(scrListOffs + (i * 8) + 4, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); writer.Write(Scripts.Values.ToArray()[i].Write()); while ((writer.BaseStream.Length & 0xF) != 0x0 && (writer.BaseStream.Length & 0xF) != 0x4 && (writer.BaseStream.Length & 0xF) != 0x8 && (writer.BaseStream.Length & 0xF) != 0xC) { writer.Write((byte)0); } } writer.BaseStream.Seek(0x24, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); writer.Write((long)0); while ((writer.BaseStream.Length & 0xF) != 0x0 && (writer.BaseStream.Length & 0xF) != 0x4 && (writer.BaseStream.Length & 0xF) != 0x8 && (writer.BaseStream.Length & 0xF) != 0xC) { writer.Write((byte)0); } for (int i = 0; i < Namespaces.Count; i++) { writer.BaseStream.Seek(0x34 + (i * 20) + 4, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Namespaces[i].Name); } for (int i = 0; i < Scripts.Count; i++) { writer.BaseStream.Seek(scrListOffs + (i * 8), SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Scripts.Keys.ToArray()[i]); } XData.UpdateFilesize(writer); }
public MintScript(string[] text, byte[] version) { string scriptDeclare = text[0]; if (!scriptDeclare.StartsWith("script ")) { MessageBox.Show("Error: Invalid Mint Script file.", "Mint Workshop", MessageBoxButtons.OK); return; } XData = new XData(Endianness.Little, new byte[] { 2, 0 }); Version = version; Name = scriptDeclare.Substring(7); SData = new List <byte>(); XRef = new List <byte[]>(); Classes = new List <MintClass>(); Regex classRegex = new Regex("\\b(class)\\b"); Regex varRegex = new Regex("\\b(var)\\b"); Regex funcRegex = new Regex("(\\(.*\\))"); for (int l = 0; l < text.Length; l++) { string line = text[l].TrimStart(trimChars); if (line.StartsWith("//")) { continue; } if (classRegex.IsMatch(line)) { string[] classDeclaration = line.Split(' '); int classWord = classDeclaration.ToList().IndexOf("class"); MintClass newClass = new MintClass(classDeclaration[classWord + 1], 0, this); for (int i = 0; i < classWord; i++) { if (classDeclaration[i].StartsWith("flag")) { newClass.Flags |= uint.Parse(classDeclaration[i].Substring(4), NumberStyles.HexNumber); } else if (FlagLabels.ClassFlags.ContainsValue(classDeclaration[i])) { newClass.Flags |= FlagLabels.ClassFlags.Keys.ToArray()[FlagLabels.ClassFlags.Values.ToList().IndexOf(classDeclaration[i])]; } else { throw new Exception($"Unknown Class flag name \"{classDeclaration[i]}\""); } } for (int cl = l; cl < text.Length; cl++) { string classLine = text[cl].TrimStart(trimChars); if (classLine.StartsWith("//")) { continue; } if (varRegex.IsMatch(classLine)) { string[] varDeclaration = classLine.Split(' '); int varWord = varDeclaration.ToList().IndexOf("var"); MintVariable newVar = new MintVariable(varDeclaration[varWord + 2], varDeclaration[varWord + 1], 0, newClass); for (int i = 0; i < varWord; i++) { if (varDeclaration[i].StartsWith("flag")) { newVar.Flags |= uint.Parse(varDeclaration[i].Substring(4), NumberStyles.HexNumber); } else if (FlagLabels.VariableFlags.ContainsValue(varDeclaration[i])) { newVar.Flags |= FlagLabels.VariableFlags.Keys.ToArray()[FlagLabels.VariableFlags.Values.ToList().IndexOf(varDeclaration[i])]; } else { throw new Exception($"Unknown Variable flag name \"{varDeclaration[i]}\""); } } newClass.Variables.Add(newVar); } else if (funcRegex.IsMatch(classLine)) { string[] funcDeclaration = classLine.Split(' '); string name = ""; uint funcFlags = 0; for (int i = 0; i < funcDeclaration.Length; i++) { if (funcDeclaration[i].StartsWith("flag")) { funcFlags |= uint.Parse(funcDeclaration[i].Substring(4), NumberStyles.HexNumber); } else if (FlagLabels.FunctionFlags.ContainsValue(funcDeclaration[i])) { funcFlags |= FlagLabels.FunctionFlags.Keys.ToArray()[FlagLabels.FunctionFlags.Values.ToList().IndexOf(funcDeclaration[i])]; } else { name = string.Join(" ", funcDeclaration.Skip(i)); break; } } MintFunction newFunc = new MintFunction(name, funcFlags, newClass); List <string> instructions = new List <string>(); for (int fl = cl + 2; fl < text.Length; fl++) { string funcLine = text[fl].TrimStart(trimChars); if (funcLine.StartsWith("//")) { continue; } if (funcLine.StartsWith("}")) { cl = fl; break; } instructions.Add(funcLine); } newFunc.Assemble(instructions.ToArray()); newFunc.DetectArguments(); newFunc.DetectRegisters(); newClass.Functions.Add(newFunc); } else if (classLine.StartsWith("const ")) { string[] constDeclaration = classLine.Split(' '); uint value; if (constDeclaration[3].StartsWith("0x")) { value = uint.Parse(constDeclaration[3].Substring(2), NumberStyles.HexNumber); } else { value = uint.Parse(constDeclaration[3]); } newClass.Constants.Add(new MintClass.MintConstant(constDeclaration[1], value)); } else if (classLine.StartsWith("unkvalue ")) { string[] unkDeclaration = classLine.Split(' '); newClass.UnknownList.Add(uint.Parse(unkDeclaration[1])); } else if (classLine.StartsWith("unk2value ")) { string[] unkDeclaration = classLine.Split(' '); newClass.Unknown2List.Add(uint.Parse(unkDeclaration[1])); } else if (classLine.StartsWith("}")) { l = cl; break; } } Classes.Add(newClass); } } }
public byte[] Write() { using (MemoryStream stream = new MemoryStream()) using (EndianBinaryWriter writer = new EndianBinaryWriter(stream, XData.Endianness)) { XData.Write(writer); int padding = Version[0] >= 7 ? 0 : -1; uint fileStart = (uint)writer.BaseStream.Position; writer.Write(padding); if (Version[0] >= 7) { writer.Write(Hash); } uint hSdataOffset = (uint)writer.BaseStream.Position; writer.Write(Version[0] >= 7 ? 0x28 : 0x20); writer.Write(padding); writer.Write(padding); if (Version[0] >= 7) { writer.Write(padding); } writer.Write(SData.Count); writer.Write(SData.ToArray()); writer.Write((uint)0); while ((writer.BaseStream.Length & 0xF) != 0x0 && (writer.BaseStream.Length & 0xF) != 0x4 && (writer.BaseStream.Length & 0xF) != 0x8 && (writer.BaseStream.Length & 0xF) != 0xC) { writer.Write((byte)0); } writer.BaseStream.Seek(hSdataOffset + 0x4, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); writer.Write(XRef.Count); for (int i = 0; i < XRef.Count; i++) { writer.Write(XRef[i]); } writer.BaseStream.Seek(hSdataOffset + 0x8, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); uint classListOffs = (uint)writer.BaseStream.Position; writer.Write(Classes.Count); for (int i = 0; i < Classes.Count; i++) { writer.Write(padding); } List <uint> classNameOffs = new List <uint>(); List <uint[]> varNameOffs = new List <uint[]>(); List <uint[]> funcNameOffs = new List <uint[]>(); List <uint[]> constNameOffs = new List <uint[]>(); for (int i = 0; i < Classes.Count; i++) { writer.BaseStream.Seek(classListOffs + 4 + (i * 4), SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); uint cl = (uint)writer.BaseStream.Position; classNameOffs.Add(cl); writer.Write(padding); writer.Write(Classes[i].Hash); writer.Write(padding); writer.Write(padding); writer.Write(padding); if (Version[0] >= 2 || Version[1] >= 1) { writer.Write(padding); } if (Version[0] >= 7) { writer.Write(padding); } writer.Write(Classes[i].Flags); bool writeVariables = true; //if (Version[0] >= 7) // writeVariables = Classes[i].Variables.Count > 0; List <uint> vOffs = new List <uint>(); if (writeVariables) { writer.BaseStream.Seek(cl + 0x8, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); uint varListOffs = (uint)writer.BaseStream.Position; writer.Write(Classes[i].Variables.Count); for (int v = 0; v < Classes[i].Variables.Count; v++) { writer.Write((uint)(varListOffs + 4 + (Classes[i].Variables.Count * 4) + (v * 0x10))); } for (int v = 0; v < Classes[i].Variables.Count; v++) { vOffs.Add((uint)writer.BaseStream.Position); writer.Write(padding); writer.Write(Classes[i].Variables[v].Hash); writer.Write(padding); writer.Write(Classes[i].Variables[v].Flags); } } bool writeFunctions = true; //if (Version[0] >= 7) // writeFunctions = Classes[i].Functions.Count > 0; List <uint> funcOffsList = new List <uint>(); if (writeFunctions) { writer.BaseStream.Seek(cl + 0xC, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); uint funcListOffs = (uint)writer.BaseStream.Position; writer.Write(Classes[i].Functions.Count); for (int v = 0; v < Classes[i].Functions.Count; v++) { writer.Write(padding); } for (int v = 0; v < Classes[i].Functions.Count; v++) { writer.BaseStream.Seek(funcListOffs + 4 + (v * 4), SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); funcOffsList.Add((uint)writer.BaseStream.Length); writer.Write(padding); writer.Write(Classes[i].Functions[v].Hash); if (Version[0] >= 7) { writer.Write(Classes[i].Functions[v].Arguments); writer.Write(Classes[i].Functions[v].Registers); } if (Version[0] >= 2 || Version[1] >= 1) //Only 2.x and 1.1.x use function flags { writer.Write((uint)writer.BaseStream.Position + 8); writer.Write(Classes[i].Functions[v].Flags); } else { writer.Write((uint)writer.BaseStream.Position + 4); } for (int f = 0; f < Classes[i].Functions[v].Instructions.Count; f++) { Classes[i].Functions[v].Instructions[f].Write(writer); } } } bool writeConstants = true; if (Version[0] >= 7) { writeConstants = Classes[i].Constants.Count > 0; } List <uint> cOffs = new List <uint>(); if (writeConstants) { writer.BaseStream.Seek(cl + 0x10, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); writer.Write(Classes[i].Constants.Count); uint constListOffs = (uint)writer.BaseStream.Position; for (int v = 0; v < Classes[i].Constants.Count; v++) { writer.Write((uint)(constListOffs + (Classes[i].Constants.Count * 4) + (v * 8))); } for (int v = 0; v < Classes[i].Constants.Count; v++) { cOffs.Add((uint)writer.BaseStream.Position); writer.Write(padding); writer.Write(Classes[i].Constants[v].Value); } } bool writeUnkSection = false; if (Version[0] >= 2 || Version[1] >= 1) { writeUnkSection = true; } else if (Version[0] >= 7) { writeUnkSection = Classes[i].UnknownList.Count > 0; } if (writeUnkSection) { writer.BaseStream.Seek(cl + 0x14, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); writer.Write(Classes[i].UnknownList.Count); for (int v = 0; v < Classes[i].UnknownList.Count; v++) { writer.Write(Classes[i].UnknownList[v]); } } bool writeUnk2Section = false; if (Version[0] >= 7) { writeUnk2Section = Classes[i].Unknown2List.Count > 0; } if (writeUnk2Section) { writer.BaseStream.Seek(cl + 0x18, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); writer.Write(Classes[i].Unknown2List.Count); for (int v = 0; v < Classes[i].Unknown2List.Count; v++) { writer.Write(Classes[i].Unknown2List[v]); } } varNameOffs.Add(vOffs.ToArray()); funcNameOffs.Add(funcOffsList.ToArray()); constNameOffs.Add(cOffs.ToArray()); } //String writing writer.BaseStream.Seek(0x10, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Name); for (int i = 0; i < Classes.Count; i++) { writer.BaseStream.Seek(classNameOffs[i], SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Classes[i].Name); if (Version[0] < 7 || Classes[i].Variables.Count > 0) { for (int v = 0; v < Classes[i].Variables.Count; v++) { uint vo = varNameOffs[i][v]; writer.BaseStream.Seek(vo, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Classes[i].Variables[v].Name); writer.BaseStream.Seek(vo + 0x8, SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Classes[i].Variables[v].Type); } } if (Version[0] < 7 || Classes[i].Functions.Count > 0) { for (int v = 0; v < Classes[i].Functions.Count; v++) { writer.BaseStream.Seek(funcNameOffs[i][v], SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Classes[i].Functions[v].Name); } } if (Version[0] < 7 || Classes[i].Constants.Count > 0) { for (int v = 0; v < Classes[i].Constants.Count; v++) { writer.BaseStream.Seek(constNameOffs[i][v], SeekOrigin.Begin); writer.Write((uint)writer.BaseStream.Length); writer.BaseStream.Seek(0, SeekOrigin.End); WriteUtil.WriteString(writer, Classes[i].Constants[v].Name); } } } XData.UpdateFilesize(writer); return(stream.GetBuffer().Take((int)XData.Filesize).ToArray()); } }