Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and enhance StringConverter() to handle more special characters #361

Merged
merged 17 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions nanoFramework.Json.Test/Converters/StringConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,43 @@ public void StringConverter_ToJson_Should_ReturnValidData(string value, string e

Assert.AreEqual(expectedValue, convertedValue);
}

[TestMethod]
[DataRow("Text\\1", "Text\\1")] // Backslash
[DataRow("Text\b1", "Text\b1")] // Backspace
[DataRow("Text\f1", "Text\f1")] // FormFeed
[DataRow("Text\r1", "Text\r1")] // CarriageReturn
[DataRow("Text\"1", "Text\"1")] // DoubleQuote
[DataRow("Text\n1", "Text\n1")] // Newline
[DataRow("Text\t1", "Text\t1")] // Tab
[DataRow("['Text3', 1]", "['Text3', 1]")] // Array
[DataRow("{\"Text1\" : \"/Text1/\"}", "{\"Text1\" : \"/Text1/\"}")] // Json
[DataRow("ä", "ä")] // Unicode
[DataRow("\"I:\\\\nano\\\\rpath\\\\to\"", "I:\\nano\\rpath\\to")]
public void StringConverter_ToType_Should_HandleSpecialCharacters(string value, string expectedValue)
{
var converter = new Json.Converters.StringConverter();
var convertedValue = (string)converter.ToType(value);

Assert.AreEqual(expectedValue, convertedValue);
}

[TestMethod]
[DataRow("Text\\1", "\"Text\\\\1\"")] // Backslash
[DataRow("Text\b1", "\"Text\\b1\"")] // Backspace
[DataRow("Text\f1", "\"Text\\f1\"")] // FormFeed
[DataRow("Text\r1", "\"Text\\r1\"")] // CarriageReturn
[DataRow("Text\"1", "\"Text\\\"1\"")] // DoubleQuote
[DataRow("Text\n1", "\"Text\\n1\"")] // Newline
[DataRow("Text\t1", "\"Text\\t1\"")] // Tab
[DataRow("ä", "\"ä\"")] // Unicode
[DataRow("I:\\nano\\rpath\\to", "\"I:\\\\nano\\\\rpath\\\\to\"")]
public void StringConverter_ToJson_Should_HandleSpecialCharacters(string value, string expectedValue)
{
var converter = new Json.Converters.StringConverter();
var convertedValue = converter.ToJson(value);

Assert.AreEqual(expectedValue, convertedValue);
}
}
}
28 changes: 28 additions & 0 deletions nanoFramework.Json.Test/JsonSerializerOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,34 @@ public void Can_serialize_and_deserialize_escaped_string()
Assert.AreEqual(thing.Value, deserialized.Value);
}

[TestMethod]
public void Can_serialize_and_deserialize_object_containing_string_with_multiple_escaped_characters()
{
var thing = new ThingWithString
{
Value = "I:\\Nano\\rApp\\app.pe"
};

var serialized = JsonConvert.SerializeObject(thing);
var deserialized = (ThingWithString)JsonConvert.DeserializeObject(serialized, typeof(ThingWithString));
Assert.AreEqual(thing.Value, deserialized.Value);
}

[TestMethod]
public void Can_serialize_and_deserialize_string_with_multiple_escaped_characters()
{
var testValue = "I:\\Nano\\rApp\\app.pe";
Console.WriteLine("Original: " + testValue);

var serialized = JsonConvert.SerializeObject(testValue);
Console.WriteLine("Serialized: " + serialized);

var deserialized = (string)JsonConvert.DeserializeObject(serialized, typeof(string));
Console.WriteLine("Deserialized: " + deserialized);

Assert.AreEqual(testValue, deserialized);
}

[TestMethod]
public void Can_serialize_and_deserialize_complex_object()
{
Expand Down
18 changes: 16 additions & 2 deletions nanoFramework.Json/Converters/StringConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ internal sealed class StringConverter : IConverter
{
{'\n', 'n'},
{'\r', 'r'},
{'\b', 'b' },
{'\f', 'f' },
{'\t', 't' },
{'\\', '\\' },
{'\"', '"' }
};

Expand Down Expand Up @@ -97,8 +101,18 @@ public object ToType(object value)
return value;
}

//String by default has escaped \" at beggining and end, just remove them
var resultString = sourceString.Substring(1, sourceString.Length - 2);
string resultString;

// String by default has escaped \" at beggining and end, just remove them
// if they have already been removed, string has likely already been deserialized,
// and if so, then we just return it.
if (!sourceString.StartsWith("\"") && !sourceString.EndsWith("\""))
{
return sourceString;
}

resultString = sourceString.Substring(1, sourceString.Length - 2);

var newString = new StringBuilder();
//Last character can not be escaped, because it's last one
for (int i = 0; i < resultString.Length - 1; i++)
Expand Down
54 changes: 30 additions & 24 deletions nanoFramework.Json/JsonConvert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,32 +1088,38 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
return EndToken(sb);
}

//TODO: replace with a mapping array? This switch is really incomplete.
switch (ch)
if(ch == 'u')
{
case 't':
ch = '\t';
break;

case 'r':
ch = '\r';
break;

case 'n':
ch = '\n';
break;

case 'u':
unicodeEncoded = true;
break;

case '"':
ch = '"';
break;

default:
throw new DeserializationException();
unicodeEncoded = true;
}

mizady marked this conversation as resolved.
Show resolved Hide resolved
//TODO: replace with a mapping array? This switch is really incomplete.
// Has been moved to StringConverter but unicode part still remains here
//switch (ch)
//{
// case 't':
// ch = '\t';
// break;

// case 'r':
// ch = '\r';
// break;

// case 'n':
// ch = '\n';
// break;

// case 'u':
// unicodeEncoded = true;
// break;

// case '"':
// ch = '"';
// break;

// default:
// throw new DeserializationException();
//}
}

if ((sb != null) && ((ch != openQuote) || (escaped)))
Expand Down