@@ -25,12 +25,24 @@ public static JSONData ParseJson(string json)
25
25
/// </summary>
26
26
public class JSONData
27
27
{
28
- public enum DataType { Object , Array , String } ;
28
+ public enum DataType
29
+ {
30
+ Object ,
31
+ Array ,
32
+ String
33
+ } ;
34
+
29
35
private readonly DataType type ;
30
- public DataType Type { get { return type ; } }
36
+
37
+ public DataType Type
38
+ {
39
+ get { return type ; }
40
+ }
41
+
31
42
public Dictionary < string , JSONData > Properties ;
32
43
public List < JSONData > DataArray ;
33
44
public string StringValue ;
45
+
34
46
public JSONData ( DataType datatype )
35
47
{
36
48
type = datatype ;
@@ -63,12 +75,21 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
63
75
if ( toparse [ cursorpos ] == '"' )
64
76
{
65
77
JSONData propertyname = String2Data ( toparse , ref cursorpos ) ;
66
- if ( toparse [ cursorpos ] == ':' ) { cursorpos ++ ; } else { /* parse error ? */ }
78
+ if ( toparse [ cursorpos ] == ':' )
79
+ {
80
+ cursorpos ++ ;
81
+ }
82
+ else
83
+ {
84
+ /* parse error ? */
85
+ }
86
+
67
87
JSONData propertyData = String2Data ( toparse , ref cursorpos ) ;
68
88
data . Properties [ propertyname . StringValue ] = propertyData ;
69
89
}
70
90
else cursorpos ++ ;
71
91
}
92
+
72
93
cursorpos ++ ;
73
94
break ;
74
95
@@ -79,10 +100,15 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
79
100
SkipSpaces ( toparse , ref cursorpos ) ;
80
101
while ( toparse [ cursorpos ] != ']' )
81
102
{
82
- if ( toparse [ cursorpos ] == ',' ) { cursorpos ++ ; }
103
+ if ( toparse [ cursorpos ] == ',' )
104
+ {
105
+ cursorpos ++ ;
106
+ }
107
+
83
108
JSONData arrayItem = String2Data ( toparse , ref cursorpos ) ;
84
109
data . DataArray . Add ( arrayItem ) ;
85
110
}
111
+
86
112
cursorpos ++ ;
87
113
break ;
88
114
@@ -103,9 +129,11 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
103
129
&& IsHex ( toparse [ cursorpos + 5 ] ) )
104
130
{
105
131
//"abc\u0123abc" => "0123" => 0123 => Unicode char n°0123 => Add char to string
106
- data . StringValue += char . ConvertFromUtf32 ( int . Parse ( toparse . Substring ( cursorpos + 2 , 4 ) ,
132
+ data . StringValue += char . ConvertFromUtf32 ( int . Parse (
133
+ toparse . Substring ( cursorpos + 2 , 4 ) ,
107
134
System . Globalization . NumberStyles . HexNumber ) ) ;
108
- cursorpos += 6 ; continue ;
135
+ cursorpos += 6 ;
136
+ continue ;
109
137
}
110
138
else if ( toparse [ cursorpos + 1 ] == 'n' )
111
139
{
@@ -127,12 +155,20 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
127
155
}
128
156
else cursorpos ++ ; //Normal character escapement \"
129
157
}
130
- catch ( IndexOutOfRangeException ) { cursorpos ++ ; } // \u01<end of string>
131
- catch ( ArgumentOutOfRangeException ) { cursorpos ++ ; } // Unicode index 0123 was invalid
158
+ catch ( IndexOutOfRangeException )
159
+ {
160
+ cursorpos ++ ;
161
+ } // \u01<end of string>
162
+ catch ( ArgumentOutOfRangeException )
163
+ {
164
+ cursorpos ++ ;
165
+ } // Unicode index 0123 was invalid
132
166
}
167
+
133
168
data . StringValue += toparse [ cursorpos ] ;
134
169
cursorpos ++ ;
135
170
}
171
+
136
172
cursorpos ++ ;
137
173
break ;
138
174
@@ -151,47 +187,93 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
151
187
case '-' :
152
188
data = new JSONData ( JSONData . DataType . String ) ;
153
189
StringBuilder sb = new ( ) ;
154
- while ( ( toparse [ cursorpos ] >= '0' && toparse [ cursorpos ] <= '9' ) || toparse [ cursorpos ] == '.' || toparse [ cursorpos ] == '-' )
190
+ while ( ( toparse [ cursorpos ] >= '0' && toparse [ cursorpos ] <= '9' ) || toparse [ cursorpos ] == '.' ||
191
+ toparse [ cursorpos ] == '-' )
155
192
{
156
193
sb . Append ( toparse [ cursorpos ] ) ;
157
194
cursorpos ++ ;
158
195
}
196
+
159
197
data . StringValue = sb . ToString ( ) ;
160
198
break ;
161
199
162
200
//Boolean : true
163
201
case 't' :
164
202
data = new JSONData ( JSONData . DataType . String ) ;
165
203
cursorpos ++ ;
166
- if ( toparse [ cursorpos ] == 'r' ) { cursorpos ++ ; }
167
- if ( toparse [ cursorpos ] == 'u' ) { cursorpos ++ ; }
168
- if ( toparse [ cursorpos ] == 'e' ) { cursorpos ++ ; data . StringValue = "true" ; }
204
+ if ( toparse [ cursorpos ] == 'r' )
205
+ {
206
+ cursorpos ++ ;
207
+ }
208
+
209
+ if ( toparse [ cursorpos ] == 'u' )
210
+ {
211
+ cursorpos ++ ;
212
+ }
213
+
214
+ if ( toparse [ cursorpos ] == 'e' )
215
+ {
216
+ cursorpos ++ ;
217
+ data . StringValue = "true" ;
218
+ }
219
+
169
220
break ;
170
221
171
222
//Boolean : false
172
223
case 'f' :
173
224
data = new JSONData ( JSONData . DataType . String ) ;
174
225
cursorpos ++ ;
175
- if ( toparse [ cursorpos ] == 'a' ) { cursorpos ++ ; }
176
- if ( toparse [ cursorpos ] == 'l' ) { cursorpos ++ ; }
177
- if ( toparse [ cursorpos ] == 's' ) { cursorpos ++ ; }
178
- if ( toparse [ cursorpos ] == 'e' ) { cursorpos ++ ; data . StringValue = "false" ; }
226
+ if ( toparse [ cursorpos ] == 'a' )
227
+ {
228
+ cursorpos ++ ;
229
+ }
230
+
231
+ if ( toparse [ cursorpos ] == 'l' )
232
+ {
233
+ cursorpos ++ ;
234
+ }
235
+
236
+ if ( toparse [ cursorpos ] == 's' )
237
+ {
238
+ cursorpos ++ ;
239
+ }
240
+
241
+ if ( toparse [ cursorpos ] == 'e' )
242
+ {
243
+ cursorpos ++ ;
244
+ data . StringValue = "false" ;
245
+ }
246
+
179
247
break ;
180
248
181
249
//Null field
182
250
case 'n' :
183
251
data = new JSONData ( JSONData . DataType . String ) ;
184
252
cursorpos ++ ;
185
- if ( toparse [ cursorpos ] == 'u' ) { cursorpos ++ ; }
186
- if ( toparse [ cursorpos ] == 'l' ) { cursorpos ++ ; }
187
- if ( toparse [ cursorpos ] == 'l' ) { cursorpos ++ ; data . StringValue = "null" ; }
253
+ if ( toparse [ cursorpos ] == 'u' )
254
+ {
255
+ cursorpos ++ ;
256
+ }
257
+
258
+ if ( toparse [ cursorpos ] == 'l' )
259
+ {
260
+ cursorpos ++ ;
261
+ }
262
+
263
+ if ( toparse [ cursorpos ] == 'l' )
264
+ {
265
+ cursorpos ++ ;
266
+ data . StringValue = "null" ;
267
+ }
268
+
188
269
break ;
189
270
190
271
//Unknown data
191
272
default :
192
273
cursorpos ++ ;
193
274
return String2Data ( toparse , ref cursorpos ) ;
194
275
}
276
+
195
277
SkipSpaces ( toparse , ref cursorpos ) ;
196
278
return data ;
197
279
}
@@ -206,7 +288,10 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
206
288
/// </summary>
207
289
/// <param name="c">Char to test</param>
208
290
/// <returns>True if hexadecimal</returns>
209
- private static bool IsHex ( char c ) { return ( ( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'F' ) || ( c >= 'a' && c <= 'f' ) ) ; }
291
+ private static bool IsHex ( char c )
292
+ {
293
+ return ( ( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'F' ) || ( c >= 'a' && c <= 'f' ) ) ;
294
+ }
210
295
211
296
/// <summary>
212
297
/// Advance the cursor to skip white spaces and line breaks
@@ -216,10 +301,77 @@ private static JSONData String2Data(string toparse, ref int cursorpos)
216
301
private static void SkipSpaces ( string toparse , ref int cursorpos )
217
302
{
218
303
while ( cursorpos < toparse . Length
219
- && ( char . IsWhiteSpace ( toparse [ cursorpos ] )
220
- || toparse [ cursorpos ] == '\r '
221
- || toparse [ cursorpos ] == '\n ' ) )
304
+ && ( char . IsWhiteSpace ( toparse [ cursorpos ] )
305
+ || toparse [ cursorpos ] == '\r '
306
+ || toparse [ cursorpos ] == '\n ' ) )
222
307
cursorpos ++ ;
223
308
}
309
+
310
+ // Original: https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
311
+ private static bool NeedEscape ( string src , int i )
312
+ {
313
+ var c = src [ i ] ;
314
+ return c < 32 || c == '"' || c == '\\ '
315
+ // Broken lead surrogate
316
+ || ( c is >= '\uD800 ' and <= '\uDBFF ' &&
317
+ ( i == src . Length - 1 || src [ i + 1 ] < '\uDC00 ' || src [ i + 1 ] > '\uDFFF ' ) )
318
+ // Broken tail surrogate
319
+ || ( c is >= '\uDC00 ' and <= '\uDFFF ' &&
320
+ ( i == 0 || src [ i - 1 ] < '\uD800 ' || src [ i - 1 ] > '\uDBFF ' ) )
321
+ // To produce valid JavaScript
322
+ || c == '\u2028 ' || c == '\u2029 '
323
+ // Escape "</" for <script> tags
324
+ || ( c == '/' && i > 0 && src [ i - 1 ] == '<' ) ;
325
+ }
326
+
327
+ public static string EscapeString ( string src )
328
+ {
329
+ var sb = new StringBuilder ( ) ;
330
+ var start = 0 ;
331
+
332
+ for ( var i = 0 ; i < src . Length ; i ++ )
333
+ {
334
+ if ( ! NeedEscape ( src , i ) ) continue ;
335
+ sb . Append ( src , start , i - start ) ;
336
+
337
+ switch ( src [ i ] )
338
+ {
339
+ case '\b ' :
340
+ sb . Append ( "\\ b" ) ;
341
+ break ;
342
+ case '\f ' :
343
+ sb . Append ( "\\ f" ) ;
344
+ break ;
345
+ case '\n ' :
346
+ sb . Append ( "\\ n" ) ;
347
+ break ;
348
+ case '\r ' :
349
+ sb . Append ( "\\ r" ) ;
350
+ break ;
351
+ case '\t ' :
352
+ sb . Append ( "\\ t" ) ;
353
+ break ;
354
+ case '\" ' :
355
+ sb . Append ( "\\ \" " ) ;
356
+ break ;
357
+ case '\\ ' :
358
+ sb . Append ( "\\ \\ " ) ;
359
+ break ;
360
+ case '/' :
361
+ sb . Append ( "\\ /" ) ;
362
+ break ;
363
+
364
+ default :
365
+ sb . Append ( "\\ u" ) ;
366
+ sb . Append ( ( ( int ) src [ i ] ) . ToString ( "x04" ) ) ;
367
+ break ;
368
+ }
369
+
370
+ start = i + 1 ;
371
+ }
372
+
373
+ sb . Append ( src , start , src . Length - start ) ;
374
+ return sb . ToString ( ) ;
375
+ }
224
376
}
225
- }
377
+ }
0 commit comments