diff --git a/CHANGELOG.md b/CHANGELOG.md index fad0db4..97e5aa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Improvements - Exposed Camera's RoundPosition - Exposed the epsilon value used by Camera - Added Padding.Empty +- Throw an exception when text formatter macros resolve recursively too many times ### MLEM.Ui Additions diff --git a/MLEM/Formatting/TextFormatter.cs b/MLEM/Formatting/TextFormatter.cs index f7584c7..ad1fb9b 100644 --- a/MLEM/Formatting/TextFormatter.cs +++ b/MLEM/Formatting/TextFormatter.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -114,6 +115,7 @@ namespace MLEM.Formatting { /// The final, recursively resolved string public string ResolveMacros(string s) { // resolve macros that resolve into macros + var rec = 0; bool matched; do { matched = false; @@ -124,6 +126,9 @@ namespace MLEM.Formatting { return macro.Value(this, m, macro.Key); }); } + rec++; + if (rec >= 16) + throw new ArithmeticException($"A string resolved macros recursively too many times. Does it contain any conflicting macros?\n{s}"); } while (matched); return s; } diff --git a/Tests/FontTests.cs b/Tests/FontTests.cs index 6ac1366..3ab2998 100644 --- a/Tests/FontTests.cs +++ b/Tests/FontTests.cs @@ -1,3 +1,4 @@ +using System; using System.Text.RegularExpressions; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -107,6 +108,11 @@ namespace Tests { const string strg = "This text uses a bunch of non-breaking~spaces to see if macros work. Additionally, it uses a macro that resolves into a bunch of other macros and then, at the end, into text."; const string goal = "This text uses a bunch of non-breaking\u00A0spaces to see if macros work. Additionally, it uses a macro that resolves into a bunch of other macros and then, at the end, into blue text."; Assert.AreEqual(this.formatter.ResolveMacros(strg), goal); + + // test recursive macros + this.formatter.Macros.Add(new Regex(""), (f, m, r) => ""); + this.formatter.Macros.Add(new Regex(""), (f, m, r) => ""); + Assert.Throws(() => this.formatter.ResolveMacros("Test string")); } [Test]