<commit_before>using NetSparkleUpdater.Configurations;
using NetSparkleUpdater.Enums;
using NetSparkleUpdater.Interfaces;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace NetSparkleUpdater.AppCastHandlers
{
    /// <summary>
    /// An XML-based appcast document downloader and handler
    /// </summary>
    public class XMLAppCast : IAppCastHandler
    {
        private Configuration _config;
        private string _castUrl;

        private ISignatureVerifier _signatureVerifier;
        private LogWriter _logWriter;

        private IAppCastDataDownloader _dataDownloader;

        /// <summary>
        /// Sparkle XML namespace
        /// </summary>
        public static readonly XNamespace SparkleNamespace = "http://www.andymatuschak.org/xml-namespaces/sparkle";

        /// <summary>
        /// AppCast Title
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// AppCast Language
        /// </summary>
        public string Language { get; set; }

        /// <summary>
        /// AppCastItems from the appcast
        /// </summary>
        public readonly List<AppCastItem> Items;

        /// <summary>
        /// Constructor
        /// </summary>
        public XMLAppCast()
        {
            Items = new List<AppCastItem>();
        }

        /// <summary>
        /// Sets the app cast handler up with its needed objects/parameters so that it can download
        /// and validate an appcast
        /// </summary>
        /// <param name="dataDownloader">object that will handle downloading the app cast file(s) from the internet</param>
        /// <param name="castUrl">the URL of the appcast file</param>
        /// <param name="config">the current configuration for checking which versions are installed, etc.</param>
        /// <param name="signatureVerifier">class to verify that DSA hashes are accurate</param>
        /// <param name="logWriter">object to write any log statements to</param>
        public void SetupAppCastHandler(IAppCastDataDownloader dataDownloader, string castUrl, Configuration config, ISignatureVerifier signatureVerifier, LogWriter logWriter = null)
        {
            _dataDownloader = dataDownloader;
            _config = config;
            _castUrl = castUrl;

            _signatureVerifier = signatureVerifier;
            _logWriter = logWriter ?? new LogWriter();
        }

        /// <summary>
        /// Download castUrl resource and parse it
        /// </summary>
        public bool DownloadAndParse()
        {
            try
            {
                var appcast = _dataDownloader.DownloadAndGetAppCastData(_castUrl);
                var signature = _dataDownloader.DownloadAndGetAppCastData(_castUrl + ".dsa");
                bool didVerify = VerifyAppcast(appcast, signature);
                if (didVerify)
                {
                    ParseAppcast(appcast);
                    return true;
                }
            }
            catch (Exception e)
            {
                _logWriter.PrintMessage("Error reading app cast {0}: {1} ", _castUrl, e.Message);
            }
            return false;
        }

        private bool VerifyAppcast(string appcast, string signature)
        {
            if (appcast == null)
            {
                _logWriter.PrintMessage("Cannot read response from URL {0}", _castUrl);
                return false;
            }

            // checking signature
            var signatureNeeded = Utilities.IsSignatureNeeded(_signatureVerifier.SecurityMode, _signatureVerifier.HasValidKeyInformation());
            var appcastBytes = _dataDownloader.GetAppCastEncoding().GetBytes(appcast);
            if (signatureNeeded && _signatureVerifier.VerifySignature(signature, appcastBytes) == ValidationResult.Invalid)
            {
                _logWriter.PrintMessage("Signature check of appcast failed");
                return false;
            }
            return true;
        }

        /// <summary>
        /// Parse an XML memory stream build items list
        /// </summary>
        /// <param name="stream">The xml memory stream to parse</param>
        private void ParseAppcast(string appcast)
        {
            const string itemNode = "item";
            Items.Clear();

            XDocument doc = XDocument.Parse(appcast);
            var rss = doc?.Element("rss");
            var channel = rss?.Element("channel");

            Title = channel?.Element("title")?.Value ?? string.Empty;
            Language = channel?.Element("language")?.Value ?? "en";

            var items = doc.Descendants(itemNode);
            foreach (var item in items)
            {
                var currentItem = AppCastItem.Parse(_config.InstalledVersion, _config.ApplicationName, _castUrl, item, _logWriter);<commit_msg>AppCast is two words (camel case!)<commit_after>using NetSparkleUpdater.Configurations;
using NetSparkleUpdater.Enums;
using NetSparkleUpdater.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Linq;

namespace NetSparkleUpdater.AppCastHandlers
{
    /// <summary>
    /// An XML-based appcast document downloader and handler
    /// </summary>
    public class XMLAppCast : IAppCastHandler
    {
        private Configuration _config;
        private string _castUrl;

        private ISignatureVerifier _signatureVerifier;
        private LogWriter _logWriter;

        private IAppCastDataDownloader _dataDownloader;

        /// <summary>
        /// Sparkle XML namespace
        /// </summary>
        public static readonly XNamespace SparkleNamespace = "http://www.andymatuschak.org/xml-namespaces/sparkle";

        /// <summary>
        /// AppCast Title
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// AppCast Language
        /// </summary>
        public string Language { get; set; }

        /// <summary>
        /// AppCastItems from the appcast
        /// </summary>
        public readonly List<AppCastItem> Items;

        /// <summary>
        /// Constructor
        /// </summary>
        public XMLAppCast()
        {
            Items = new List<AppCastItem>();
        }

        /// <summary>
        /// Sets the app cast handler up with its needed objects/parameters so that it can download
        /// and validate an appcast
        /// </summary>
        /// <param name="dataDownloader">object that will handle downloading the app cast file(s) from the internet</param>
        /// <param name="castUrl">the URL of the appcast file</param>
        /// <param name="config">the current configuration for checking which versions are installed, etc.</param>
        /// <param name="signatureVerifier">class to verify that DSA hashes are accurate</param>
        /// <param name="logWriter">object to write any log statements to</param>
        public void SetupAppCastHandler(IAppCastDataDownloader dataDownloader, string castUrl, Configuration config, ISignatureVerifier signatureVerifier, LogWriter logWriter = null)
        {
            _dataDownloader = dataDownloader;
            _config = config;
            _castUrl = castUrl;

            _signatureVerifier = signatureVerifier;
            _logWriter = logWriter ?? new LogWriter();
        }

        /// <summary>
        /// Download castUrl resource and parse it
        /// </summary>
        public bool DownloadAndParse()
        {
            try
            {
                var appcast = _dataDownloader.DownloadAndGetAppCastData(_castUrl);
                var signature = _dataDownloader.DownloadAndGetAppCastData(_castUrl + ".dsa");
                bool didVerify = VerifyAppCast(appcast, signature);
                if (didVerify)
                {
                    ParseAppCast(appcast);
                    return true;
                }
            }
            catch (Exception e)
            {
                _logWriter.PrintMessage("Error reading app cast {0}: {1} ", _castUrl, e.Message);
            }
            return false;
        }

        private bool VerifyAppCast(string appcast, string signature)
        {
            if (appcast == null)
            {
                _logWriter.PrintMessage("Cannot read response from URL {0}", _castUrl);
                return false;
            }

            // checking signature
            var signatureNeeded = Utilities.IsSignatureNeeded(_signatureVerifier.SecurityMode, _signatureVerifier.HasValidKeyInformation());
            var appcastBytes = _dataDownloader.GetAppCastEncoding().GetBytes(appcast);
            if (signatureNeeded && _signatureVerifier.VerifySignature(signature, appcastBytes) == ValidationResult.Invalid)
            {
                _logWriter.PrintMessage("Signature check of appcast failed");
                return false;
            }
            return true;
        }

        /// <summary>
        /// Parse an XML memory stream build items list
        /// </summary>
        /// <param name="stream">The xml memory stream to parse</param>
        private void ParseAppCast(string appcast)
        {
            const string itemNode = "item";
            Items.Clear();

            XDocument doc = XDocument.Parse(appcast);
            var rss = doc?.Element("rss");
            var channel = rss?.Element("channel");

            Title = channel?.Element("title")?.Value ?? string.Empty;
            Language = channel?.Element("language")?.Value ?? "en";

            var items = doc.Descendants(itemNode);
            foreach (var item in items)
            {
                var currentItem = AppCastItem.Parse(_config.InstalledVersion, _config.ApplicationName, _castUrl, item, _logWriter);
{'fraction_non_alphanumeric': 0.09742665465104636, 'fraction_numerical': 0.0006007810153199159, 'mean_word_length': 1.9532820816085157, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6637038', 'n_tokens_mistral': 2501, 'n_tokens_neox': 2445, 'n_words': 666}