@@ -33,7 +33,9 @@ private struct LexToken
3333 /// <summary>
3434 /// Convert an object to a JSON string.
3535 /// </summary>
36- /// <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>
36+ /// <param name="oSource">The value to convert. Supported types are: Boolean, String, Byte, (U)Int16, (U)Int32,
37+ /// Float, Double, Decimal, Array, IDictionary, IEnumerable, Guid, Datetime, DictionaryEntry, Object and null.
38+ /// </param>
3739 /// <returns>The JSON object as a string or null when the value type is not supported.</returns>
3840 /// <remarks>For objects, only public properties with getters are converted.</remarks>
3941 public static string SerializeObject ( object oSource )
@@ -1088,7 +1090,7 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
10881090 return EndToken ( sb ) ;
10891091 }
10901092
1091- //TODO: replace with a mapping array? This switch is really incomplete.
1093+ // handle escaped characters
10921094 switch ( ch )
10931095 {
10941096 case 't' :
@@ -1115,15 +1117,21 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
11151117 ch = '\\ ' ;
11161118 break ;
11171119
1118- case 'u' :
1119- unicodeEncoded = true ;
1120- break ;
1121-
11221120 case '"' :
11231121 ch = '"' ;
11241122 break ;
11251123
1124+ case '\' ' :
1125+ ch = '\' ' ;
1126+ break ;
1127+
1128+ case 'u' :
1129+ // unicode escape \uXXXX - we'll handle below
1130+ unicodeEncoded = true ;
1131+ break ;
1132+
11261133 default :
1134+ // unknown escape sequence
11271135 throw new DeserializationException ( ) ;
11281136 }
11291137 }
@@ -1132,56 +1140,32 @@ private static LexToken GetNextTokenInternal(ref int jsonPos, ref byte[] jsonByt
11321140 {
11331141 if ( unicodeEncoded )
11341142 {
1135- int numberCounter = 0 ;
1136-
1137- // next 4 chars have to be numeric
1138- StringBuilder encodedValue = new ( ) ;
1139-
1140- // advance position to next char
1141- jsonPos ++ ;
1142- ch = ( char ) jsonBytes [ jsonPos ] ;
1143-
1144- for ( int i = 0 ; i < 4 ; i ++ )
1143+ // We must decode exactly 4 hex digits following the '\u'
1144+ // Ensure there are at least 4 bytes remaining
1145+ if ( jsonPos + 4 > jsonBytes . Length )
11451146 {
1146- if ( IsNumberChar ( ch ) )
1147- {
1148- numberCounter ++ ;
1149-
1150- encodedValue . Append ( ch ) ;
1151-
1152- ch = ( char ) jsonBytes [ jsonPos ] ;
1153-
1154- if ( IsNumberChar ( ch ) )
1155- {
1156- // We're still working on the number - advance jsonPos
1157- jsonPos ++ ;
1158- }
1159- }
1147+ throw new DeserializationException ( ) ;
11601148 }
11611149
1162- if ( numberCounter == 4 )
1150+ // Read 4 ASCII hex chars (they should be ASCII hex digits)
1151+ int val = 0 ;
1152+ for ( int i = 0 ; i < 4 ; i ++ )
11631153 {
1164- // we're good with the encoded data
1165- // try parse number as an UTF-8 char
1166- try
1167- {
1168- // NOTE: the encoded value has hexadecimal format
1169- int unicodeChar = Convert . ToInt16 ( encodedValue . ToString ( ) , 16 ) ;
1170-
1171- _ = sb . Append ( ( char ) unicodeChar ) ;
1172- }
1173- catch
1154+ char hc = ( char ) jsonBytes [ jsonPos ++ ] ;
1155+ int digit ;
1156+ if ( hc >= '0' && hc <= '9' ) digit = hc - '0' ;
1157+ else if ( hc >= 'a' && hc <= 'f' ) digit = 10 + ( hc - 'a' ) ;
1158+ else if ( hc >= 'A' && hc <= 'F' ) digit = 10 + ( hc - 'A' ) ;
1159+ else
11741160 {
1175- // couldn't parse this number as a valid Unicode value
11761161 throw new DeserializationException ( ) ;
11771162 }
1163+
1164+ val = ( val << 4 ) + digit ;
11781165 }
1179- else
1180- {
1181- // anything else, we can't parse it properly
1182- // throw exception
1183- throw new DeserializationException ( ) ;
1184- }
1166+
1167+ // Append the decoded unicode character
1168+ sb . Append ( ( char ) val ) ;
11851169 }
11861170 else
11871171 {
0 commit comments