Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
26 changes: 26 additions & 0 deletions nanoFramework.Json.Test/JsonSerializerOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,32 @@ public void Can_serialize_and_deserialize_arrays_of_class_objects()
OutputHelper.WriteLine("");
}

[TestMethod]
public void Can_deserialize_string_starting_with_unicode_escape()
{

OutputHelper.WriteLine("Starting test...");

Console.WriteLine($"{TimeSpan.FromHours(1).TotalMilliseconds}");

JsonTestCompany test = new JsonTestCompany
{
CompanyID = 10,
CompanyName = "5 Guys"
};

var jsonString = "{\u0022CompanyID\u0022:10,\u0022CompanyName\u0022:\u00225 Guys\u0022}";


JsonTestCompany deserializedResult = (JsonTestCompany)JsonConvert.DeserializeObject(jsonString, typeof(JsonTestCompany));

Assert.NotNull(deserializedResult);
Assert.Equal("5 Guys", deserializedResult.CompanyName);
Assert.Equal(10, deserializedResult.CompanyID);

OutputHelper.WriteLine("Finished test...");
}

[TestMethod]
public void Can_serialize_and_deserialize_arrays_of_class_objects_when_array_items_may_be_null()
{
Expand Down
81 changes: 33 additions & 48 deletions nanoFramework.Json/JsonConvert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ private struct LexToken
/// <summary>
/// Convert an object to a JSON string.
/// </summary>
/// <param name="oSource">The value to convert. Supported types are: Boolean, String, Byte, (U)Int16, (U)Int32, Float, Double, Decimal, Array, IDictionary, IEnumerable, Guid, Datetime, DictionaryEntry, Object and null.</param>
/// <param name="oSource">
/// The value to convert. Supported types are: Boolean, String, Byte, (U)Int16, (U)Int32,
/// Float, Double, Decimal, Array, IDictionary, IEnumerable, Guid, Datetime, DictionaryEntry, Object and null.
/// </param>
/// <returns>The JSON object as a string or null when the value type is not supported.</returns>
/// <remarks>For objects, only public properties with getters are converted.</remarks>
public static string SerializeObject(object oSource)
Expand Down Expand Up @@ -1088,7 +1091,7 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
return EndToken(sb);
}

//TODO: replace with a mapping array? This switch is really incomplete.
// handle escaped characters
switch (ch)
{
case 't':
Expand All @@ -1115,15 +1118,21 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
ch = '\\';
break;

case 'u':
unicodeEncoded = true;
break;

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

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

case 'u':
// unicode escape \uXXXX - we'll handle below
unicodeEncoded = true;
break;

default:
// unknown escape sequence
throw new DeserializationException();
}
}
Expand All @@ -1132,56 +1141,32 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
{
if (unicodeEncoded)
{
int numberCounter = 0;

// next 4 chars have to be numeric
StringBuilder encodedValue = new();

// advance position to next char
jsonPos++;
ch = (char)jsonBytes[jsonPos];

for (int i = 0; i < 4; i++)
// We must decode exactly 4 hex digits following the '\u'
// Ensure there are at least 4 bytes remaining
if (jsonPos + 4 > jsonBytes.Length)
{
if (IsNumberChar(ch))
{
numberCounter++;

encodedValue.Append(ch);

ch = (char)jsonBytes[jsonPos];

if (IsNumberChar(ch))
{
// We're still working on the number - advance jsonPos
jsonPos++;
}
}
throw new DeserializationException();
}

if (numberCounter == 4)
// Read 4 ASCII hex chars (they should be ASCII hex digits)
int val = 0;
for (int i = 0; i < 4; i++)
{
// we're good with the encoded data
// try parse number as an UTF-8 char
try
{
// NOTE: the encoded value has hexadecimal format
int unicodeChar = Convert.ToInt16(encodedValue.ToString(), 16);

_ = sb.Append((char)unicodeChar);
}
catch
char hc = (char)jsonBytes[jsonPos++];
int digit;
if (hc >= '0' && hc <= '9') digit = hc - '0';
else if (hc >= 'a' && hc <= 'f') digit = 10 + (hc - 'a');
else if (hc >= 'A' && hc <= 'F') digit = 10 + (hc - 'A');
else
{
// couldn't parse this number as a valid Unicode value
throw new DeserializationException();
}

val = (val << 4) + digit;
}
else
{
// anything else, we can't parse it properly
// throw exception
throw new DeserializationException();
}

// Append the decoded unicode character
sb.Append((char)val);
}
else
{
Expand Down
Loading