using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.IO; using System.Globalization; namespace NonaBGS.Journal { public class JournalFile : IComparable { private string fullpath = null; private string part = null; private int intpart = 0; private DateTime datetime; private DateTime normalised; private List entries = new List(); private static Regex fileregex = new Regex("Journal\\.(\\d+)\\.(\\d+)\\.log"); private static string iso8601 = "yyyyMMddTHHmmss"; private static string iso8601_notime = "yyyyMMdd"; public static bool VerifyFile(string path) { string filename = Path.GetFileName(path); var matches = fileregex.Matches(filename); return matches.Count != 0; } 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 < 1) { throw new JournalException(string.Format("Invalid journal file: {0}", filename)); } this.fullpath = path; this.part = matches[0].Groups[2].ToString(); this.intpart = int.Parse(part); // 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(matches[0].Groups[1].ToString()); date.Insert(8, "T"); // Add the "T" separating date and time this.datetime = DateTime.ParseExact(date.ToString(), iso8601, CultureInfo.InvariantCulture); this.normalised = DateTime.Parse(this.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 intpart - other.intpart; } else { return comp; } } public JournalFile(string path) { SetFilename(path); } public DateTime Timestamp { get { return datetime; } } public DateTime NormalisedTimestamp { get { return normalised; } } public int Part { get { return intpart; } } 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(this.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) { Entry entry = Entry.Parse(line); entries.Add(entry); } } } }