EDBGS/EDPlayerJournal/JournalFile.cs
Florian Stinglmayr d6842115c5 no longer completely fail on one wrong entry
U17 might have caused some journal bugs so don't fail immediately on one wrong entry, instead keep them in an Errors collection for later processing
2023-10-25 11:30:34 +02:00

150 lines
4.7 KiB
C#

using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using EDPlayerJournal.Entries;
namespace EDPlayerJournal;
public class JournalFile : IComparable<JournalFile>
{
public string FullPath { get; set; }
public int Part { get; set; }
public DateTime? DateTime { get; set; }
public DateTime? NormalisedDateTime { get; set; }
public List<Entry> entries = new List<Entry>();
private static Regex fileregex = new Regex("Journal\\.(\\d+)\\.(\\d+)\\.log");
private static Regex update11regex = new Regex("Journal\\.([^\\.]+)\\.(\\d+).log");
private static string iso8601 = "yyyyMMddTHHmmss";
/// <summary>
/// A public list of errors encountered while parsing the journal files
/// </summary>
public List<Exception> Errors { get; private set; } = new List<Exception>();
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 = System.DateTime.ParseExact(timestamp, iso8601, CultureInfo.InvariantCulture);
this.Part = int.Parse(part);
this.NormalisedDateTime = System.DateTime.Parse(DateTime.Value.ToShortDateString());
}
public int CompareTo(JournalFile? other) {
if (other == null || DateTime == null || other.DateTime == null) {
return 0;
}
var comp = System.DateTime.Compare(DateTime.Value, other.DateTime.Value);
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) {
FullPath = "";
SetFilename(path);
}
public IEnumerable<Entry> Entries {
get {
if (entries == null || entries.Count == 0) {
try {
LoadEntries();
} catch (IOException) {
}
if (entries == null) {
entries = new List<Entry>();
}
}
return entries;
}
}
public void LoadEntries() {
List<string> lines = new List<string>();
/* 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;
while ((line = sr.ReadLine()) != null) {
lines.Add(line);
}
}
}
entries.Clear();
Errors.Clear();
foreach (var line in lines) {
// Skip empty lines
if (line.Trim().Length == 0) {
continue;
}
try {
Entry? entry = Entry.Parse(line);
if (entry != null) {
entries.Add(entry);
}
} catch (Exception ex) {
Errors.Add(ex);
}
}
}
}