From 7e381d61f664466f61ba33c113cc6626c4cd551c Mon Sep 17 00:00:00 2001 From: punchready Date: Sun, 8 May 2022 10:01:02 +0200 Subject: [PATCH] fix: use more robust parsing of large timespans --- TShockAPI/Commands.cs | 6 ++-- TShockAPI/Utils.cs | 76 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 6b7f3259..7cfdc182 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -1512,7 +1512,7 @@ namespace TShockAPI } } - if (TShock.Utils.TryParseTime(duration, out int seconds)) + if (TShock.Utils.TryParseTime(duration, out ulong seconds)) { expiration = DateTime.UtcNow.AddSeconds(seconds); } @@ -1880,7 +1880,7 @@ namespace TShockAPI if (args.Parameters.Count > 2) { - int time; + ulong time; if (!TShock.Utils.TryParseTime(args.Parameters[2], out time)) { args.Player.SendErrorMessage("Invalid time string! Proper format: _d_h_m_s, with at least one time specifier."); @@ -1888,7 +1888,7 @@ namespace TShockAPI return; } - ply[0].tempGroupTimer = new System.Timers.Timer(time * 1000); + ply[0].tempGroupTimer = new System.Timers.Timer(time * 1000d); ply[0].tempGroupTimer.Elapsed += ply[0].TempGroupTimerElapsed; ply[0].tempGroupTimer.Start(); } diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index cb38a5ea..9dcbbd84 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -607,6 +607,82 @@ namespace TShockAPI return true; } + /// + /// Attempts to parse a string as a positive timespan (_d_m_h_s). + /// + /// The time string. + /// The seconds. + /// Whether the string was parsed successfully. + public bool TryParseTime(string str, out ulong seconds) + { + seconds = 0; + + if (string.IsNullOrWhiteSpace(str)) + { + return false; + } + + var sb = new StringBuilder(3); + for (int i = 0; i < str.Length; i++) + { + if (char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+' || str[i] == ' ')) + sb.Append(str[i]); + else + { + int num; + if (!int.TryParse(sb.ToString().Trim(' '), out num)) + return false; + + sb.Clear(); + + if (num == 0) + { + continue; + } + + int numSeconds; + switch (str[i]) + { + case 's': + numSeconds = num; + break; + case 'm': + numSeconds = num * 60; + break; + case 'h': + numSeconds = num * 60 * 60; + break; + case 'd': + numSeconds = num * 60 * 60 * 24; + break; + default: + return false; + } + + if (numSeconds > 0) + { + if (ulong.MaxValue - seconds < (uint)numSeconds) + { + return false; + } + + seconds += (uint)numSeconds; + } + else if (seconds >= (uint)Math.Abs(numSeconds)) + { + seconds -= (uint)Math.Abs(numSeconds); + } + else + { + return false; + } + } + } + if (sb.Length != 0) + return false; + return true; + } + /// /// Searches for a projectile by identity and owner ///