From 49dbe37ac9d5c6b209fa33adc76b3e0a51a7e7c4 Mon Sep 17 00:00:00 2001 From: Benjamin Sutas Date: Mon, 19 Feb 2024 13:52:34 +1100 Subject: [PATCH 1/3] fix off-by-one string table parse error --- Core/DatFileParsing/SawyerStreamReader.cs | 53 ++++++++++++----------- Core/Data/LanguageId.cs | 6 +-- Core/Objects/TrainSignalObject.cs | 16 ++++++- Gui/Gui.csproj | 3 +- Gui/MainFormModel.cs | 2 +- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/Core/DatFileParsing/SawyerStreamReader.cs b/Core/DatFileParsing/SawyerStreamReader.cs index d8d4cf8b..b497c5bc 100644 --- a/Core/DatFileParsing/SawyerStreamReader.cs +++ b/Core/DatFileParsing/SawyerStreamReader.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using OpenLoco.ObjectEditor.Headers; using OpenLoco.ObjectEditor.Objects; using OpenLoco.ObjectEditor.Types; @@ -154,12 +154,30 @@ public static (DatFileInfo DatFileInfo, ILocoObject? LocoObject) LoadFullObjectF return new(new DatFileInfo(s5Header, objectHeader), newObj); } + public static string CStringToString(ReadOnlySpan data, Encoding enc) + { + var ptr = 0; + while (data[ptr++] != '\0') ; + return enc.GetString(data[0..(ptr - 1)]); // do -1 to exclude the \0 + } + + static Dictionary GetNewLanguageDictionary() + { + var languageDict = new Dictionary(); + foreach (var language in Enum.GetValues()) + { + languageDict.Add(language, string.Empty); + } + return languageDict; + } + public static (StringTable table, int bytesRead) LoadStringTable(ReadOnlySpan data, string[] stringNames, ILogger? logger = null) { var stringTable = new StringTable(); if (data.Length == 0 || stringNames.Length == 0) { + logger?.Warning($"No data for language table"); return (stringTable, 0); } @@ -167,37 +185,22 @@ public static (StringTable table, int bytesRead) LoadStringTable(ReadOnlySpan()) - { - languageDict.Add(language, string.Empty); - } - - for (; ptr < data.Length && data[ptr] != 0xFF;) + // read string + for (; ptr < data.Length && data[ptr] != 0xFF; ++ptr) { var lang = (LanguageId)data[ptr++]; - var ini = ptr; - - while (data[ptr++] != '\0') - { - ; - } - - var str = Encoding.Latin1.GetString(data[ini..(ptr - 1)]); // do -1 to exclude the \0 - - if (!languageDict.ContainsKey(lang)) - { - logger?.Error($"Skipping unknown language: \"{lang}\""); - break; - } - - languageDict[lang] = str; + languageDict[lang] = CStringToString(data[ptr..], Encoding.Latin1); + ptr += languageDict[lang].Length; } ptr++; // add one because we skipped the 0xFF byte at the end + + //data = data[ptr..]; + //ptr = 0; } return (stringTable, ptr); diff --git a/Core/Data/LanguageId.cs b/Core/Data/LanguageId.cs index 44fb6bec..7dbd3973 100644 --- a/Core/Data/LanguageId.cs +++ b/Core/Data/LanguageId.cs @@ -1,4 +1,4 @@ -namespace OpenLoco.ObjectEditor.Data +namespace OpenLoco.ObjectEditor.Data { public enum LanguageId : uint8_t { @@ -16,7 +16,7 @@ public enum LanguageId : uint8_t chinese_traditional, id_12, portuguese, - blank = 254, - end = 255 + //blank = 254, + //end = 255 }; } diff --git a/Core/Objects/TrainSignalObject.cs b/Core/Objects/TrainSignalObject.cs index 81ee2e4d..b1e6854b 100644 --- a/Core/Objects/TrainSignalObject.cs +++ b/Core/Objects/TrainSignalObject.cs @@ -1,7 +1,8 @@ -using System.ComponentModel; +using System.ComponentModel; using OpenLoco.ObjectEditor.Data; using OpenLoco.ObjectEditor.DatFileParsing; using OpenLoco.ObjectEditor.Headers; +using OpenLoco.ObjectEditor.Types; namespace OpenLoco.ObjectEditor.Objects { @@ -33,7 +34,7 @@ public record TrainSignalObject( [property: LocoStructOffset(0x13), LocoArrayLength(TrainSignalObject.ModsLength), Browsable(false)] object_id[] ModHeaderIds, [property: LocoStructOffset(0x1A)] uint16_t DesignedYear, [property: LocoStructOffset(0x1C)] uint16_t ObsoleteYear - ) : ILocoStruct, ILocoStructVariableData + ) : ILocoStruct, ILocoStructVariableData, IImageTableStrings { public const int ModsLength = 7; @@ -49,5 +50,16 @@ public ReadOnlySpan Save() => Mods .SelectMany(mod => mod.Write().ToArray()) .ToArray(); + + public bool TryGetImageName(int id, out string? value) + => ImageIdNameMap.TryGetValue(id, out value); + + public static Dictionary ImageIdNameMap = new() + { + { 80, "redLights" }, + { 88, "redLights2" }, + { 96, "greenLights" }, + { 104, "greenLights2" }, + }; } } diff --git a/Gui/Gui.csproj b/Gui/Gui.csproj index 37703629..14e514a7 100644 --- a/Gui/Gui.csproj +++ b/Gui/Gui.csproj @@ -17,6 +17,7 @@ LeftofZen $(AssemblyName) $(AssemblyVersion) $(AssemblyVersion) + False @@ -45,8 +46,8 @@ - + diff --git a/Gui/MainFormModel.cs b/Gui/MainFormModel.cs index 19eac03f..c394a6ef 100644 --- a/Gui/MainFormModel.cs +++ b/Gui/MainFormModel.cs @@ -363,7 +363,7 @@ static void SerialiseHeaderIndexToFile(string filename, HeaderIndex headerIndex, } else { - var obj = SawyerStreamReader.LoadFullObjectFromFile(filename); + var obj = SawyerStreamReader.LoadFullObjectFromFile(filename, logger: logger); var uiObj = new UiLocoObject { DatFileInfo = obj.DatFileInfo, LocoObject = obj.LocoObject }; _ = ObjectCache.TryAdd(filename, uiObj); return uiObj; From 34a4592667424769634a1602b9c266232c0b93de Mon Sep 17 00:00:00 2001 From: Benjamin Sutas Date: Mon, 19 Feb 2024 13:58:06 +1100 Subject: [PATCH 2/3] code cleanup --- Core/DatFileParsing/SawyerStreamReader.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/DatFileParsing/SawyerStreamReader.cs b/Core/DatFileParsing/SawyerStreamReader.cs index b497c5bc..ac3e9b54 100644 --- a/Core/DatFileParsing/SawyerStreamReader.cs +++ b/Core/DatFileParsing/SawyerStreamReader.cs @@ -198,9 +198,6 @@ public static (StringTable table, int bytesRead) LoadStringTable(ReadOnlySpan Date: Mon, 19 Feb 2024 13:59:02 +1100 Subject: [PATCH 3/3] code cleanup --- Core/DatFileParsing/SawyerStreamReader.cs | 2 +- Gui/Gui.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/DatFileParsing/SawyerStreamReader.cs b/Core/DatFileParsing/SawyerStreamReader.cs index ac3e9b54..9bc29b5e 100644 --- a/Core/DatFileParsing/SawyerStreamReader.cs +++ b/Core/DatFileParsing/SawyerStreamReader.cs @@ -154,7 +154,7 @@ public static (DatFileInfo DatFileInfo, ILocoObject? LocoObject) LoadFullObjectF return new(new DatFileInfo(s5Header, objectHeader), newObj); } - public static string CStringToString(ReadOnlySpan data, Encoding enc) + static string CStringToString(ReadOnlySpan data, Encoding enc) { var ptr = 0; while (data[ptr++] != '\0') ; diff --git a/Gui/Gui.csproj b/Gui/Gui.csproj index 14e514a7..5487cf5d 100644 --- a/Gui/Gui.csproj +++ b/Gui/Gui.csproj @@ -46,8 +46,8 @@ - +