using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.IO; using System.Globalization; namespace EDJournal { public class JournalFile : IComparable { public string FullPath { get; set; } public int Part { get; set; } public DateTime DateTime { get; set; } public DateTime NormalisedDateTime { get; set; } public List entries = new List(); private static Regex fileregex = new Regex("Journal\\.(\\d+)\\.(\\d+)\\.log"); private static Regex update11regex = new Regex("Journal\\.([^\\.]+)\\.(\\d+).log"); private static string iso8601 = "yyyyMMddTHHmmss"; public static bool VerifyFile(string path) { string filename = Path.GetFileName(path); var matches = fileregex.Matches(filename); if (matches.Count != 0) { return true; } matches = update11regex.Matches(filename); if (matches.Count != 0) { return true; } return false; } private void SetFilename(string path) { string filename = Path.GetFileName(path); if (!File.Exists(path) || filename == null) { throw new JournalException(string.Format("Invalid journal file: {0}", filename)); } var matches = fileregex.Matches(filename); if (matches.Count == 0) { matches = update11regex.Matches(filename); if (matches.Count == 0) { throw new JournalException(string.Format("invalid file format: {0}", filename)); } } FullPath = path; var groups = matches[0].Groups; string part = groups[2].ToString(); string timestamp = groups[1].ToString(); if (!timestamp.Contains("T")) { /* pre update 11 file */ // The ISO is not quite correct on journal filenames, so build // a proper ISO 8601 date time stamp out of it. var date = new StringBuilder(); date.Append("20"); // Add the missing century in front. date.Append(timestamp); date.Insert(8, "T"); // Add the "T" separating date and time timestamp = date.ToString(); } else { /* post update 11 file, remove dashes */ timestamp = timestamp.Replace("-", ""); } this.DateTime = DateTime.ParseExact(timestamp, iso8601, CultureInfo.InvariantCulture); this.Part = int.Parse(part); this.NormalisedDateTime = DateTime.Parse(DateTime.ToShortDateString()); } public int CompareTo(JournalFile other) { if (DateTime == null || other.DateTime == null) { return 0; } var comp = DateTime.Compare(DateTime, other.DateTime); if (comp == 0) { /* If we have the exact same datetime we compare by parts. */ return Part - other.Part; } else { return comp; } } public JournalFile(string path) { SetFilename(path); } public IEnumerable Entries { get { if (entries == null || entries.Count == 0) { try { LoadEntries(); } catch (IOException) { entries = new List(); } } return entries; } } public void LoadEntries() { List lines = new List(); /* This needs to be done this way, otherwise, if the game is still running the journal files cannot * be accessed. And it is very much convenient to generate logs while the game is still running. */ using (var fs = new FileStream(FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (var sr = new StreamReader(fs, Encoding.UTF8)) { string line = null; while ((line = sr.ReadLine()) != null) { lines.Add(line); } } } entries.Clear(); foreach(var line in lines) { // Skip empty lines if (line.Trim().Length == 0) { continue; } Entry entry = Entry.Parse(line); entries.Add(entry); } } } }