Skip to content

Commit

Permalink
Parser handles numeric overflow better; fix bug
Browse files Browse the repository at this point in the history
CHANGE: The JSON parser now parses numbers that cannot be represented as a double-precision float
    using -Infinity (if they have a leading - sign) or Infinity. Previously they were parsed as NaN.
FIX: Fix improperly named tree view for grepper form when JsonTools is translated into another language
    (that bug was introduced in 8.1.0.4)
  • Loading branch information
molsonkiko committed Sep 18, 2024
1 parent dead63e commit 593f1ee
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 60 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Changed

1. If a [JSON lines document](/docs/README.md#json-lines-documents) is not compliant with the strict JSON specification, the [status bar](/docs/README.md#error-form-and-status-bar) will now reflect that it is JSON lines.
1. If a number string is too large or small for a 64-bit floating point number (for example, `-2e700`, `3.5e+450`), the JSON parser will now represent them as `-Infinity` (if they have a leading `-` sign) or `Infinity`, rather than representing them as `NaN`. The linter also has a new message for when this happens.
2. If a [JSON lines document](/docs/README.md#json-lines-documents) is not compliant with the strict JSON specification, the [status bar](/docs/README.md#error-form-and-status-bar) will now reflect that it is JSON lines.

### Fixed

Expand Down
9 changes: 5 additions & 4 deletions JsonToolsNppPlugin/Forms/TreeViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,18 +1479,19 @@ public void Rename(string newFname, bool isFilename)

/// <summary>
/// sets this.ptrTitleBuf to a pointer to an unmanaged Unicode char array containing the title of this TreeViewer's docking form.<br></br>
/// If isFilename, strips the directory name away from the beginning of title.
/// If isFilename, inserts the title (after stripping the directory name away from the beginning of title) into the normal format string for the TreeViewer title
/// </summary>
public IntPtr SetTitleBuffer(string title, bool isFilename)
{
string fullTitle = title;
if (isFilename)
{
string[] fnameSplit = fname.Split('\\');
title = fnameSplit[fnameSplit.Length - 1];
string defaultNameFormat = "Json Tree View for {0}";
string nameFormat = (Translator.TryGetTranslationAtPath(new string[] { "forms", "TreeViewer", "title" }, out JNode node) && node.value is string s && s.Contains("{0}")) ? s : defaultNameFormat;
fullTitle = nameFormat.Replace("{0}", title);
}
string defaultNameFormat = "Json Tree View for {0}";
string nameFormat = (Translator.TryGetTranslationAtPath(new string[] { "forms", "TreeViewer", "title" }, out JNode node) && node.value is string s && s.Contains("{0}")) ? s : defaultNameFormat;
string fullTitle = nameFormat.Replace("{0}", title);
int maxCharsTitleBuf = MAX_LEN_TITLE_BUFFER / Marshal.SystemDefaultCharSize - 1;
if (fullTitle.Length > maxCharsTitleBuf)
fullTitle = fullTitle.Substring(0, maxCharsTitleBuf - 3) + "...";
Expand Down
18 changes: 15 additions & 3 deletions JsonToolsNppPlugin/JSONTools/JsonParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ public string TranslateMessageIfDesired(bool translated)
case JsonLintType.BAD_PYTHON_False: return Translator.TranslateLintMessage(translated, lintType, "False is not allowed in any JSON specification");
case JsonLintType.BAD_JAVASCRIPT_undefined: return Translator.TranslateLintMessage(translated, lintType, "undefined is not allowed in any JSON specification");
case JsonLintType.BAD_CHAR_INSTEAD_OF_EOF: return TryTranslateWithOneParam(translated, lintType, "At end of valid JSON document, got {0} instead of EOF", param1);
case JsonLintType.BAD_FLOAT_TOO_LARGE: return TryTranslateWithOneParam(translated, lintType, "Number string {0} is too large for a 64-bit floating point number", param1);
// FATAL messages
case JsonLintType.FATAL_EXPECTED_JAVASCRIPT_COMMENT: return Translator.TranslateLintMessage(translated, lintType, "Expected JavaScript comment after '/'");
case JsonLintType.FATAL_HEXADECIMAL_TOO_SHORT: return TryTranslateWithOneParam(translated, lintType, "Could not find valid hexadecimal of length {0}", param1);
Expand Down Expand Up @@ -355,6 +356,10 @@ public enum JsonLintType : short
/// param1 = c (char)
/// </summary>
BAD_CHAR_INSTEAD_OF_EOF = BAD_UNTERMINATED_MULTILINE_COMMENT + 31,
/// <summary>
/// param1 = numStr (string)
/// </summary>
BAD_FLOAT_TOO_LARGE = BAD_UNTERMINATED_MULTILINE_COMMENT + 32,
// ========== FATAL errors =============
FATAL_EXPECTED_JAVASCRIPT_COMMENT = (ParserState.FATAL - 1) << 10,
/// <summary>
Expand Down Expand Up @@ -1357,10 +1362,17 @@ public JNode ParseNumber(string inp)
{
num = double.Parse(numstr, JNode.DOT_DECIMAL_SEP);
}
catch
catch (Exception ex)
{
HandleError(JsonLintType.BAD_NUMBER_INVALID_FORMAT, inp, startUtf8Pos, JNode.StrToString(numstr, true));
num = NanInf.nan;
var errno = JsonLintType.BAD_NUMBER_INVALID_FORMAT;
if (ex is OverflowException)
{
num = negative ? NanInf.neginf : NanInf.inf;
errno = JsonLintType.BAD_FLOAT_TOO_LARGE;
}
else
num = NanInf.nan;
HandleError(errno, inp, startUtf8Pos, JNode.StrToString(numstr, true));
}
if (numstr[numstr.Length - 1] == '.')
HandleError(JsonLintType.JSON5_NUM_TRAILING_DECIMAL_POINT, inp, startUtf8Pos);
Expand Down
4 changes: 2 additions & 2 deletions JsonToolsNppPlugin/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
// Build Number
// Revision
//
[assembly: AssemblyVersion("8.1.0.6")]
[assembly: AssemblyFileVersion("8.1.0.6")]
[assembly: AssemblyVersion("8.1.0.7")]
[assembly: AssemblyFileVersion("8.1.0.7")]
13 changes: 12 additions & 1 deletion JsonToolsNppPlugin/Tests/JsonParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,10 @@ instead got
new object[] { "{}", "{" + NL + " }", true },
new object[] { "[]", "[ ]", true },
new object[] { "[]", "[1, 2]", false },
new object[] { "1" + new string('0', 400), "NaN", true }, // really really big int representations
new object[] { "1" + new string('0', 400), "Infinity", true }, // really really big int representations
new object[] { "-2" + new string('3', 350), "-Infinity", true }, // really really big int representations (negative)
new object[] { "-2.1234567890e700", "-Infinity", true }, // really really big float representations (negative)
new object[] { "5.43433666464342343433341e4550", "Infinity", true }, // really really big float representations (positive)
};
foreach (object[] test in equalityTestcases)
{
Expand Down Expand Up @@ -1083,6 +1086,14 @@ public static bool TestLinter()
"Numbers with an unnecessary leading 0 (like \"01\") are not allowed in any JSON specification",
"Numbers with an unnecessary leading 0 (like \"01\") are not allowed in any JSON specification",
}),
("[9.7642E+857, -23e500, 3e-, +" + new string('3', 400) + "]", "[Infinity, -Infinity, NaN, Infinity]", new string[]
{
"Number string \"9.7642E+857\" is too large for a 64-bit floating point number",
"Number string \"-23e500\" is too large for a 64-bit floating point number",
"Number string \"3e-\" had bad format",
"Leading + signs in numbers are only allowed in JSON5",
"Number string \"+" + new string('3', 400) + "\" is too large for a 64-bit floating point number",
}),
};

int testsFailed = 0;
Expand Down
Loading

0 comments on commit 593f1ee

Please sign in to comment.