/// <summary> /// Constructs based on XML game. /// </summary> /// <param name="xmlGame">Parsed game from PinballX XML database</param> public AggregatedGame([NotNull] PinballXGame xmlGame) : this(Locator.Current) { Update(xmlGame); FileId = Path.Combine(xmlGame.System.TablePath, xmlGame.FileName); // Unlink local file when table path changes. XmlGame.WhenAnyValue(g => g.System.TablePath).Subscribe(newPath => ClearLocalFile()); }
/// <summary> /// Updates XML game. /// </summary> /// <param name="xmlGame">Parsed game from PinballX XML database</param> /// <returns>This instance</returns> public AggregatedGame Update(PinballXGame xmlGame) { if (XmlGame == null) { XmlGame = xmlGame; } else { XmlGame.Update(xmlGame); } return(this); }
/// <summary> /// Renames the file ID of the game. /// </summary> /// /// <remarks> /// This happens when a local file with a mapping has been renamed. In /// this case we want to keep the mapping linked to the game. The /// mapping is renamed as well. /// </remarks> /// /// <param name="filePath">Absolute path to new file name</param> /// <param name="newXmlGame">If set, link to this XML game. This means that an entry with the new file name exists already and its mapping will be overwritten existing.</param> public void Rename(string filePath, PinballXGame newXmlGame = null) { if (!HasMapping || !HasLocalFile) { throw new InvalidOperationException("Can only rename games with mapping and local file."); } Update(filePath); if (newXmlGame != null) { XmlGame = newXmlGame; } Mapping.Rename(filePath); }
public void RemoveGame(PinballXGame game) { // read current xml var xmlPath = Path.Combine(game.System.DatabasePath, _settingsManager.Settings.XmlFile[game.System.Type] + ".xml"); _logger.Info("Removing \"{0}\" from PinballX database at {1}", game.Description, xmlPath); if (_settingsManager.Settings.ReformatXml) { var menu = _marshallManager.UnmarshallXml(xmlPath); var gameToRemove = menu.Games.FirstOrDefault(g => g.Description == game.Description && g.FileName == game.FileName); if (gameToRemove == null) { _logger.Warn("Could not find game in existing XML, aborting."); return; } // remove game menu.Games.Remove(gameToRemove); // save xml _marshallManager.MarshallXml(menu, xmlPath); } else { // match with regex var xml = _file.ReadAllText(xmlPath); var gameBlock = new Regex("<game\\s[^>]*name=\"" + Regex.Escape(game.FileName) + "\".*?<\\/game> *[\\n\\r]?", RegexOptions.IgnoreCase | RegexOptions.Singleline); _logger.Info("Trying to match {0}", gameBlock); var match = gameBlock.Match(xml); var offset = 0; while (match.Success) { if (match.Groups[0].Value.Contains("<description>" + game.Description + "</description>")) { _logger.Info("Got match: {0}", match.Groups[0]); xml = xml.Substring(0, match.Index - offset) + xml.Substring(match.Index + match.Length - offset); offset += match.Length; } match = match.NextMatch(); } // write back to disk _file.WriteAllText(xmlPath, xml); } }
public void AddGame(AggregatedGame game) { if (game.HasXmlGame) { throw new InvalidOperationException("Game already in XML database."); } if (game.MappedRelease == null || game.MappedTableFile == null) { throw new InvalidOperationException("Cannot add game without release mapping."); } var xmlGame = new PinballXGame { FileName = Path.GetFileNameWithoutExtension(game.FileDisplayName), Description = $"{game.MappedRelease.Game.Title} ({game.MappedRelease.Game.Manufacturer} {game.MappedRelease.Game.Year})", Manufacturer = game.MappedRelease.Game.Manufacturer, Year = game.MappedRelease.Game.Year.ToString(), System = game.System }; _pinballXManager.AddGame(xmlGame); }
public PinballXGame AddGame(PinballXGame game) { // read current xml var xmlPath = Path.Combine(game.System.DatabasePath, _settingsManager.Settings.XmlFile[game.System.Type] + ".xml"); _logger.Info("Adding \"{0}\" to PinballX database at {1}", game.Description, xmlPath); if (_settingsManager.Settings.ReformatXml || !_file.Exists(xmlPath)) { var menu = _marshallManager.UnmarshallXml(xmlPath); // add game menu.Games.Add(game); // save xml _marshallManager.MarshallXml(menu, xmlPath); } else { var xml = _file.ReadAllText(xmlPath); var ns = new XmlSerializerNamespaces(); ns.Add("", ""); using (var writer = new StringWriter()) { // find out how the xml is indented var match = Regex.Match(xml, "[\n\r]([ \t]+)<", RegexOptions.Multiline | RegexOptions.IgnoreCase); var indentChars = match.Success ? match.Groups[1].ToString() : " "; // find the position where to insert game if (xml.IndexOf("</menu", StringComparison.OrdinalIgnoreCase) < 0) { xml = "<menu>\n\n</menu>"; } // serialize game as xml using (var xw = XmlWriter.Create(writer, new XmlWriterSettings { IndentChars = indentChars, Indent = true })) { var serializer = new XmlSerializer(typeof(PinballXGame)); serializer.Serialize(xw, game, ns); var xmlGame = string.Join("\n", writer .ToString() .Split('\n') .Select(line => line.StartsWith("<?xml") ? "" : line) .Select(line => indentChars + line) .ToList()) + "\n"; var pos = xml.LastIndexOf("</menu", StringComparison.OrdinalIgnoreCase); // insert game xml = xml.Substring(0, pos) + xmlGame + xml.Substring(pos); // write back to disk _file.WriteAllText(xmlPath, xml); _logger.Info("Appended game \"{0}\" to {1}", game.Description, xmlPath); } } } return(game); }
/// <summary> /// Checks if the XML game is equal, i.e. the data is equal (to /// check if it should be updated). /// </summary> /// <param name="xmlGame">XML game to compare</param> /// <returns>True if equal, false otherwise</returns> public bool EqualsXmlGame(PinballXGame xmlGame) { return(XmlGame != null && XmlGame.Equals(xmlGame)); }