public override void BuildSignature() { if (isSignatureBuilt) { return; } Program.Log(LogLevel.NOR, "Building Signature for Packet[" + Header.PadRight(4, ' ') + "][" + Desc + "]"); bool doesSubcatePlaceholderAppeared = false; bool packetBodySectionEnded = false; bool isInSubcate = false; bool isRepeatableTagEnded = true; string tmpSignature = ""; // subcate is not replaced yet JArray infoBeforeSubcate = new JArray(); JArray infoAfterSubcate = new JArray(); dynamic tmpObj = new JObject(); string tmpSubcateSignature = ""; JArray tmpSubcateInfo = new JArray(); foreach (var(num, code) in Lines) { var(sign, infos) = ParseSignatureLine(code); Program.CurrentLine = num; if (infos != null) { if (isInSubcate) { tmpSubcateSignature += " " + sign; tmpSubcateInfo.Add(infos); } else { tmpSignature += " " + sign; if (doesSubcatePlaceholderAppeared) { infoAfterSubcate.Add(infos); } else { infoBeforeSubcate.Add(infos); } } } else { if (code.StartsWith("+ Fragment")) { var obj = Fragment.GetFragmentByCode(code); tmpSignature += " " + obj.Signature; // add range obj.Infos.ForEach(info => infoBeforeSubcate.Add(info)); } else if (code.StartsWith("+ SubCate")) { // set constraint, only 1 subcate code can be used if (doesSubcatePlaceholderAppeared) { Program.Log(LogLevel.ERR | LogLevel.EXIT, "Constraint Violation - You can only use 1 \"+ SubCate\" within same packet/fragment.", "Occurred within: Packet[" + Header.PadRight(4, ' ') + "] " + Desc ); } else if (packetBodySectionEnded) { Program.Log(LogLevel.ERR | LogLevel.EXIT, "Constraint Violation - You cannot include another subcate within a subcate.", "Occurred within: Packet[" + Header.PadRight(4, ' ') + "] " + Desc ); } tmpSignature += " {SUBCATE}"; doesSubcatePlaceholderAppeared = true; } else if (code.StartsWith("SubCate[")) { // start of subcate signature var m = regexSubcate.Match(code); var g = m.Groups; if (!m.Success || (g[1].Value == "" && g[2].Value == "")) { Program.Log(LogLevel.ERR | LogLevel.EXIT, "Invalid SubCate declaration.", "Occurred within: Packet[" + Header.PadRight(4, ' ') + "] " + Desc, "Captured: [" + string.Join(", ", g.Values) + "]", "Raw: " + code ); } // have subcate before this subcate (another) // push the previous subcate to dict list if (isInSubcate) { if (tmpSignature == "") { Program.Log(LogLevel.WARN, "Skipped invalid SubCate declaration - No actual signature/body.", "Occurred within: Packet[" + Header.PadRight(4, ' ') + "] " + Desc ); } else { subcate.Add(tmpSubcateSignature.TrimStart(), tmpObj); } } tmpObj = new JObject(); // renew tmpObj.desc = g[1].Value; tmpObj["params"] = tmpSubcateInfo = new JArray(); tmpSubcateSignature = ""; if (g[2].Value != "") { // with hex-byte (static hex subcate signature) tmpSubcateSignature += " " + g[2].Value[1..];
static void Main(string[] cmdArgs) { Version version = Assembly.GetExecutingAssembly().GetName().Version; AssemblyDescriptionAttribute releaseDate = (AssemblyDescriptionAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyDescriptionAttribute)); Console.WriteLine($"============== Signature Builder - For Parser rev5 ==============\r\n" + $"\t+ Build: {version} [{releaseDate.Description}]\r\n\r\n"); var file = (cmdArgs.Length >= 1 ? cmdArgs[0] : ".") + "/parser.txt"; var outFile = (cmdArgs.Length >= 2 ? cmdArgs[1] : ".") + "/_pkts.v5.ignore.json"; if (!System.IO.File.Exists(file)) { Log(LogLevel.ERR | LogLevel.EXIT, "File not found @ " + file); } string[] lines = System.IO.File.ReadAllLines(file); /* Example of the built output (JSON): * { * // layer 1 - packet header bytes (AKA: delimiter) * "6F": { * // layer 2 - packet infos * "name": "Hero Effect", // - packet main name * "signature": { * // layer 3 - packet signature (determines all the variants of packet body) * "$4 [REPS] $4 $1 $1 [REPE]": { * // layer 4 - infos of the matched packet signature * "desc": "", - description of this packet signature * "params": [ // - infos of each param(data) in the packet signature * { "name": "HeroID" }, // dict<string, dynamic> * { "name": "EffectID", "func": ["eHeroEffect", ] }, * // more data ... * ] * } * } * } * }*/ bool parserSectionStart = false; ParserCode obj = null; foreach (string tmp in lines) { ++CurrentLine; var line = tmp.Replace("/// ", "").Trim(); if (line == "" || line.StartsWith("//")) { continue; } // split the actual code, remove comment (//) part. if (line.Contains("//")) { line = line.Split("//")[0].Trim(); } if (line == "<parser>") { // start of parser tag parserSectionStart = true; continue; } else if (line == "</parser>") { // end of parser tag parserSectionStart = false; obj = null; continue; } if (!parserSectionStart) { // </parser> exists before but no start tag after that. Log(LogLevel.ERR | LogLevel.EXIT, "Unexpected line outside <parser> tag.", "Raw: " + line ); } if (line.StartsWith("Fragment[")) { var m = ParserCode.regexFrag.Match(line).Groups; if (m[1].Value == "") { Log(LogLevel.ERR | LogLevel.EXIT, "Malform Fragment declaration found.", "Captured: [" + string.Join(", ", m) + "]", "Raw: " + line ); } var frag = new Fragment(m[1].Value); if (!Fragment.FragmentPool.TryAdd(frag.Name, frag)) { Log(LogLevel.ERR | LogLevel.EXIT, "Failed to declare Fragment.", "Fragment Name: " + frag.Name, "Raw: " + line ); } Log(LogLevel.NOR, $"New Fragment[{frag.Name}]"); obj = frag; } else if (line.StartsWith("Packet[")) { // packet declaration var m = ParserCode.regexPkt.Match(line).Groups; if (m[1].Value == "" || m[2].Value == "") { Log(LogLevel.WARN, $"Skipped mismatch Packet Declaration", "Captured: {" + string.Join(", ", m) + "}", "Raw: " + line ); continue; } var pkt = new Packet(m[1].Value, m[2].Value.ToUpper()); if (!Packet.PacketPool.TryAdd(pkt.Header, pkt)) { Log(LogLevel.ERR | LogLevel.EXIT, $"Duplicated Packet Header[{pkt.Header}]"); } Log(LogLevel.NOR, $"New Packet[{pkt.Header,-4}] Desc[{pkt.Desc}]"); obj = pkt; } else { if (obj == null) { Log(LogLevel.ERR | LogLevel.EXIT, "Unexpected line before Packet / Fragment declaration.", "Raw: " + line ); } // push to obj's List for further parsing. obj.AddLine(CurrentLine, line); } } Console.WriteLine(""); // loop all objects to do parsing //Fragment.FragmentPool.Values.ToArray()[1].BuildSignature(); JObject mainDict = new JObject(); Fragment.FragmentPool.Values.ToList().ForEach(frag => frag.BuildSignature()); Packet.PacketPool.Values.ToList().ForEach(pkt => { pkt.BuildSignature(); mainDict.Add(pkt.Header, new JObject { { "desc", pkt.Desc }, { "signature", pkt.Signatures } }); }); // add version & timestamp mainDict.Add("_timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000); mainDict.Add("_builder", new JArray { releaseDate.Description.Split(" ")[0], "build " + version, "5" }); System.IO.File.WriteAllText(outFile, JsonConvert.SerializeObject(mainDict)); Console.WriteLine(""); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("[+] Build Success! Output File: " + outFile); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("\nPress any key to exit."); Console.ReadKey(); }