// parse route for data private void ParseRouteForData(string FileName, System.Text.Encoding Encoding, Expression[] Expressions, double[] UnitOfLength, ref RouteData Data, bool PreviewOnly) { CurrentStation = -1; CurrentStop = -1; CurrentSection = 0; string Section = ""; bool SectionAlwaysPrefix = false; int BlockIndex = 0; CurrentRoute.Stations = new RouteStation[] { }; Data.RequestStops = new StopRequest[] { }; double progressFactor = Expressions.Length == 0 ? 0.3333 : 0.3333 / Expressions.Length; // process non-track namespaces //Check for any special-cased fixes we might need CheckForAvailablePatch(FileName, ref Data, ref Expressions, PreviewOnly); //Apply parameters to object loaders if (!PreviewOnly) { for (int i = 0; i < Plugin.CurrentHost.Plugins.Length; i++) { if (Plugin.CurrentHost.Plugins[i].Object != null) { EnabledHacks.BveTsHacks = Plugin.CurrentOptions.EnableBveTsHacks; EnabledHacks.BlackTransparency = true; Plugin.CurrentHost.Plugins[i].Object.SetCompatibilityHacks(EnabledHacks); //Remember that these will be ignored if not the correct plugin Plugin.CurrentHost.Plugins[i].Object.SetObjectParser(Plugin.CurrentOptions.CurrentXParser); Plugin.CurrentHost.Plugins[i].Object.SetObjectParser(Plugin.CurrentOptions.CurrentObjParser); } } } for (int j = 0; j < Expressions.Length; j++) { Plugin.CurrentProgress = j * progressFactor; if ((j & 255) == 0) { System.Threading.Thread.Sleep(1); if (Plugin.Cancel) { Plugin.IsLoading = false; return; } } if (Expressions[j].Text.StartsWith("[") && Expressions[j].Text.EndsWith("]")) { Section = Expressions[j].Text.Substring(1, Expressions[j].Text.Length - 2).Trim(new char[] { }); if (string.Compare(Section, "object", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Structure"; } else if (string.Compare(Section, "railway", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Track"; } SectionAlwaysPrefix = true; } else { // find equals if (IsRW) { Expressions[j].ConvertRwToCsv(Section, SectionAlwaysPrefix); } // separate command and arguments string Command, ArgumentSequence; Expressions[j].SeparateCommandsAndArguments(out Command, out ArgumentSequence, Culture, false, IsRW, Section); // process command bool NumberCheck = !IsRW || string.Compare(Section, "track", StringComparison.OrdinalIgnoreCase) == 0; if (NumberCheck && NumberFormats.IsValidDouble(Command, UnitOfLength)) { // track position (ignored) } else { string[] Arguments = SplitArguments(ArgumentSequence); // preprocess command if (Command.ToLowerInvariant() == "with") { if (Arguments.Length >= 1) { Section = Arguments[0]; SectionAlwaysPrefix = false; } else { Section = ""; SectionAlwaysPrefix = false; } Command = null; } else { if (Command.StartsWith(".")) { Command = Section + Command; } else if (SectionAlwaysPrefix) { Command = Section + "." + Command; } Command = Command.Replace(".Void", ""); if (Command.StartsWith("structure", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".load", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 5).TrimEnd(new char[] { }); } else if (Command.StartsWith("texture.background", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".load", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 5).TrimEnd(new char[] { }); } else if (Command.StartsWith("texture.background", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".x", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundx" + Command.Substring(18, Command.Length - 20).TrimEnd(new char[] { }); } else if (Command.StartsWith("texture.background", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".aspect", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundaspect" + Command.Substring(18, Command.Length - 25).TrimEnd(new char[] { }); } else if (Command.StartsWith("structure.back", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".x", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundx" + Command.Substring(14, Command.Length - 16).TrimEnd(new char[] { }); } else if (Command.StartsWith("structure.back", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".aspect", StringComparison.OrdinalIgnoreCase)) { Command = "texture.backgroundaspect" + Command.Substring(14, Command.Length - 21).TrimEnd(new char[] { }); } else if (Command.StartsWith("cycle", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".params", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 7).TrimEnd(new char[] { }); } else if (Command.StartsWith("signal", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".load", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 5).TrimEnd(new char[] { }); } else if (Command.StartsWith("train.run", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".set", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 4).TrimEnd(new char[] { }); } else if (Command.StartsWith("train.flange", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".set", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 4).TrimEnd(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".day.load", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.day" + Command.Substring(15, Command.Length - 24).Trim(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".night.load", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.night" + Command.Substring(15, Command.Length - 26).Trim(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".day", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.day" + Command.Substring(15, Command.Length - 19).Trim(new char[] { }); } else if (Command.StartsWith("train.timetable", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".night", StringComparison.OrdinalIgnoreCase)) { Command = "train.timetable.night" + Command.Substring(15, Command.Length - 21).Trim(new char[] { }); } else if (Command.StartsWith("route.signal", StringComparison.OrdinalIgnoreCase) && Command.EndsWith(".set", StringComparison.OrdinalIgnoreCase)) { Command = Command.Substring(0, Command.Length - 4).TrimEnd(new char[] { }); } else if (Command.StartsWith("route.runinterval", StringComparison.OrdinalIgnoreCase)) { Command = "train.interval" + Command.Substring(17, Command.Length - 17); } else if (Command.StartsWith("train.gauge", StringComparison.OrdinalIgnoreCase)) { Command = "route.gauge" + Command.Substring(11, Command.Length - 11); } else if (Command.StartsWith("texture.", StringComparison.OrdinalIgnoreCase)) { Command = "structure." + Command.Substring(8, Command.Length - 8); } //Needed after the initial processing to make the enum parse work Command = Command.Replace("timetable.day", "timetableday"); Command = Command.Replace("timetable.night", "timetablenight"); } int[] commandIndices = FindIndices(ref Command, Expressions[j]); // process command if (!string.IsNullOrEmpty(Command)) { int period = Command.IndexOf('.'); string nameSpace = string.Empty; if (period != -1) { nameSpace = Command.Substring(0, period).ToLowerInvariant(); Command = Command.Substring(period + 1); } Command = Command.ToLowerInvariant(); switch (nameSpace) { case "options": OptionsCommand parsedOptionCommand; if (Enum.TryParse(Command, true, out parsedOptionCommand)) { ParseOptionCommand(parsedOptionCommand, Arguments, UnitOfLength, Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Options namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "route": RouteCommand parsedRouteCommand; if (Enum.TryParse(Command, true, out parsedRouteCommand)) { ParseRouteCommand(parsedRouteCommand, Arguments, commandIndices[0], FileName, UnitOfLength, Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Route namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "train": TrainCommand parsedTrainCommand; if (Enum.TryParse(Command.Split(' ')[0], true, out parsedTrainCommand)) { ParseTrainCommand(parsedTrainCommand, Arguments, commandIndices[0], Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Train namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "structure": case "texture": StructureCommand parsedStructureCommand; if (Enum.TryParse(Command, true, out parsedStructureCommand)) { ParseStructureCommand(parsedStructureCommand, Arguments, commandIndices, Encoding, Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Structure namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "": ParseSignalCommand(Command, Arguments, commandIndices[0], Encoding, Expressions[j], ref Data, PreviewOnly); break; case "cycle": CycleCommand parsedCycleCommand; if (Enum.TryParse(Command, true, out parsedCycleCommand)) { ParseCycleCommand(parsedCycleCommand, Arguments, commandIndices[0], Expressions[j], ref Data, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Cycle namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "track": break; // ReSharper disable once RedundantEmptySwitchSection default: /* * This needs an unrecognised command at some stage */ break; } } } } } // process track namespace for (int j = 0; j < Expressions.Length; j++) { Plugin.CurrentProgress = 0.3333 + j * progressFactor; if ((j & 255) == 0) { System.Threading.Thread.Sleep(1); if (Plugin.Cancel) { Plugin.IsLoading = false; return; } } if (Data.LineEndingFix) { if (Expressions[j].Text.EndsWith("_")) { Expressions[j].Text = Expressions[j].Text.Substring(0, Expressions[j].Text.Length - 1).Trim(new char[] { }); } } if (Expressions[j].Text.StartsWith("[") && Expressions[j].Text.EndsWith("]")) { Section = Expressions[j].Text.Substring(1, Expressions[j].Text.Length - 2).Trim(new char[] { }); if (string.Compare(Section, "object", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Structure"; } else if (string.Compare(Section, "railway", StringComparison.OrdinalIgnoreCase) == 0) { Section = "Track"; } SectionAlwaysPrefix = true; } else { if (IsRW) { Expressions[j].ConvertRwToCsv(Section, SectionAlwaysPrefix); } // separate command and arguments string Command, ArgumentSequence; Expressions[j].SeparateCommandsAndArguments(out Command, out ArgumentSequence, Culture, false, IsRW, Section); // process command double currentTrackPosition; bool NumberCheck = !IsRW || string.Compare(Section, "track", StringComparison.OrdinalIgnoreCase) == 0; if (NumberCheck && NumberFormats.TryParseDouble(Command, UnitOfLength, out currentTrackPosition)) { // track position if (ArgumentSequence.Length != 0) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "A track position must not contain any arguments at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); if (AllowTrackPositionArguments) { Data.TrackPosition = currentTrackPosition; BlockIndex = (int)Math.Floor(currentTrackPosition / Data.BlockInterval + 0.001); if (Data.FirstUsedBlock == -1) { Data.FirstUsedBlock = BlockIndex; } Data.CreateMissingBlocks(BlockIndex, PreviewOnly); } } else if (currentTrackPosition < 0.0) { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Negative track position encountered at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } else { if (Plugin.CurrentOptions.EnableBveTsHacks && IsRW && currentTrackPosition == 4535545100) { //WMATA Red line has an erroneous track position causing an out of memory cascade currentTrackPosition = 45355; } Data.TrackPosition = currentTrackPosition; BlockIndex = (int)Math.Floor(currentTrackPosition / Data.BlockInterval + 0.001); if (Data.FirstUsedBlock == -1) { Data.FirstUsedBlock = BlockIndex; } Data.CreateMissingBlocks(BlockIndex, PreviewOnly); } } else { string[] Arguments = SplitArguments(ArgumentSequence); // preprocess command if (Command.ToLowerInvariant() == "with") { if (Arguments.Length >= 1) { Section = Arguments[0]; SectionAlwaysPrefix = false; } else { Section = ""; SectionAlwaysPrefix = false; } Command = null; } else { if (Command.StartsWith(".")) { Command = Section + Command; } else if (SectionAlwaysPrefix) { Command = Section + "." + Command; } Command = Command.Replace(".Void", ""); } // process command if (!string.IsNullOrEmpty(Command)) { int period = Command.IndexOf('.'); string nameSpace = string.Empty; if (period != -1) { nameSpace = Command.Substring(0, period).ToLowerInvariant(); Command = Command.Substring(period + 1); } if (nameSpace.StartsWith("signal", StringComparison.InvariantCultureIgnoreCase)) { nameSpace = ""; } Command = Command.ToLowerInvariant(); switch (nameSpace) { case "track": TrackCommand parsedCommand; if (Enum.TryParse(Command, true, out parsedCommand)) { ParseTrackCommand(parsedCommand, Arguments, FileName, UnitOfLength, Expressions[j], ref Data, BlockIndex, PreviewOnly); } else { Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Unrecognised command " + Command + " encountered in the Route namespace at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); } break; case "options": case "route": case "train": case "structure": case "texture": case "": case "cycle": break; default: Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "The command " + Command + " is not supported at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File); break; } } } } } }