public static BinaryMap Decode(string gameToken, byte[] bytes) { tokens = new BinaryTokens("eu4bin.csv"); map = new BinaryMap(bytes.Length, tokens); raw = bytes; map.AddString(ANSI.GetString(raw, 0, 6), false); int i = 6; SpecialCode specialcode = SpecialCode.None; SpecialCode type = SpecialCode.None; string handler = ""; bool quoted = false; bool? list = null; bool oneLineInheritance = false; BinaryToken code = null; BinaryToken inheritedCode = null; while (i < raw.Length - 1) { // 1. Check for a special code first specialcode = GetSpecialCode(i); if (specialcode != 0) { if ((int)specialcode < 4) // brace or equals sign { ReadSpecial(ref i); // Right-brace sign clears current inheritance. if (specialcode == SpecialCode.RightBrace) { inheritedCode = null; type = SpecialCode.None; handler = ""; quoted = false; list = null; } continue; } else { // If there is attempt to redefine inherited properties, ignore it and read regardless. if (inheritedCode == null) { type = specialcode; } // Now interpret the special code. i += 2; switch (type) { case SpecialCode.String: ReadString(ref i, quoted); continue; case SpecialCode.Integer: ReadInteger(ref i); continue; case SpecialCode.Float: ReadFloat(ref i); continue; case SpecialCode.Float5: ReadFloat5(ref i); continue; case SpecialCode.Boolean: ReadBoolean(ref i); continue; case SpecialCode.Date: ReadDate(ref i, false); continue; // never quoted in practice default: break; } continue; } } // 2. No special code encountered, we are looking for a token now code = tokens.TryGetCode(raw[i], raw[i + 1]); // from little-endian code // If the token does not match anything, try to continue to read data in the same format as previously. if (code == null) { // Maybe it is an unknown token SpecialCode sc1 = GetSpecialCode(i - 2); SpecialCode sc2 = GetSpecialCode(i + 2); if (sc1 == SpecialCode.Equals || sc2 == SpecialCode.Equals) { map.AddToken("UNKNOWN_" + GetHexString(i)); i += 2; if (TryAddSpecials(ref i)) continue; TryReadTypeDefinition(ref i, ref type); } switch (type) { case SpecialCode.String: ReadString(ref i, quoted); continue; case SpecialCode.Integer: ReadInteger(ref i); continue; case SpecialCode.Float: ReadFloat(ref i); continue; case SpecialCode.Float5: ReadFloat5(ref i); continue; case SpecialCode.Boolean: ReadBoolean(ref i); continue; case SpecialCode.Date: ReadDate(ref i, quoted); continue; default: break; } i += 2; continue; } // 3. We have found the token // Tackle inheritance: if it is on for a given token, enforce properties until the next right-brace sign. if (code.InheritType) { inheritedCode = code; type = inheritedCode.DataType; handler = inheritedCode.Text; quoted = inheritedCode.Quoted; list = inheritedCode.List; oneLineInheritance = true; } // If no inheritance, read properties from the current token. else if (inheritedCode == null) { type = code.DataType; handler = code.Text; quoted = code.Quoted; list = code.List; } if (type == SpecialCode.Variable) // variable { // Get parent token string[] parents = map.GetParents(); InterpretCode(gameToken, handler, ref map, ref i, ref type, ref quoted, parents); continue; } else { map.AddToken(code.Text); i += 2; if (TryAddSpecials(ref i)) { oneLineInheritance = false; continue; } if (oneLineInheritance) inheritedCode = null; TryReadTypeDefinition(ref i, ref type); switch (type) { case SpecialCode.String: ReadString(ref i, quoted); continue; case SpecialCode.Integer: ReadInteger(ref i); continue; case SpecialCode.Float: ReadFloat(ref i); continue; case SpecialCode.Float5: ReadFloat5(ref i); continue; case SpecialCode.Boolean: ReadBoolean(ref i); continue; case SpecialCode.Date: ReadDate(ref i, quoted); continue; default: continue; // map.AddAttribToken(i); break; } } } map.Finish(); return map; }
private static void InterpretCode(string gameToken, string text, ref BinaryMap map, ref int i, ref SpecialCode type, ref bool quoted, string[] parents) { if (gameToken == "eu4") { switch (text) { case "type": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (IsParent(parents, 1, "id") || IsParent(parents, 1, "leader") || (IsParent(parents, 1, "rebel_faction") && IsParent(parents, -1, "provinces")) || (IsParent(parents, 1, "advisor") && IsParent(parents, -1, "active_advisors")) || IsParent(parents, 1, "monarch")) { ReadInteger(ref i); } else if ((IsParent(parents, 1, "advisor") && IsParent(parents, 3, "history")) || (IsParent(parents, 1, "advisor") && IsParent(parents, 2, "history"))) { ReadString(ref i, false); } else if (IsParent(parents, 1, "advisor")) { ReadInteger(ref i); } else if (IsParent(parents, 1, "war_goal")) { ReadString(ref i, true); } else if (IsParent(parents, 1, "general")) { map.AddToken(GetTokenText(i)); i += 2; } else if (IsParent(parents, 1, "rebel_faction") || IsParent(parents, 1, "revolt") || IsParent(parents, 1, "mercenary") || IsParent(parents, 2, "previous_war")) { ReadString(ref i, true); } else if ((IsParent(parents, 1, "regiment") && !IsParent(parents, 2, "military_construction")) || IsParent(parents, 1, "ship") || IsParent(parents, 1, "faction") || IsParent(parents, 1, "military_construction") || IsParent(parents, 1, "possible_mercenary") || IsParent(parents, 1, "active_major_mission") || IsParent(parents, 1, "casus_belli") || IsParent(parents, 1, "take_province") || IsParent(parents, 1, "take_core") || IsParent(parents, 2, "active_war")) { ReadString(ref i, false); } else { ReadInteger(ref i); } break; case "discovered_by": map.AddToken(text); i += 2; if (parents.Length > 0 && parents[parents.Length - 1].StartsWith("-")) { quoted = false; } if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); ReadString(ref i, true); break; case "action": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (IsParent(parents, 1, "diplomacy_construction")) { ReadString(ref i, true); } else if (IsParent(parents, 1, "previous_war")) { ReadDate(ref i, false); } else { ReadInteger(ref i); } break; case "steer_power": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (IsParent(parents, 1, "node")) ReadFloat(ref i); else ReadInteger(ref i); break; case "value": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (IsParent(parents, 1, "improve_relation") || IsParent(parents, 1, "warningaction")) ReadBoolean(ref i); else { ReadFloat(ref i); } break; case "unit_type": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (parents.Length > 0 && parents[parents.Length - 1].StartsWith("O0")) { map.AddToken(GetTokenText(i)); i += 2; } else { ReadString(ref i, false); } break; case "active": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (IsParent(parents, 1, "rebel_faction") || IsParent(parents, 1, "siege_combat") || IsParent(parents, 1, "combat")) { map.AddToken(GetTokenText(i)); i += 2; } else { ReadBoolean(ref i); } break; case "revolution_target": map.AddToken(text); i += 2; if (TryAddSpecials(ref i)) break; TryReadTypeDefinition(ref i, ref type); if (IsParent(parents, 2, "history")) { map.AddToken(GetTokenText(i)); i += 2; } else { ReadString(ref i, true); } break; default: i += 2; break; } } else { i += 2; } }