The R Project SVN R-packages

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7747 ripley 1
#include "JSONValidator.h"
2
 
3
#ifdef JSON_VALIDATE
4
 
5
inline bool isHex(json_char c) json_pure;
6
inline bool isHex(json_char c) json_nothrow {
7
    return (((c >= JSON_TEXT('0')) && (c <= JSON_TEXT('9'))) ||
8
		  ((c >= JSON_TEXT('A')) && (c <= JSON_TEXT('F'))) ||
9
		  ((c >= JSON_TEXT('a')) && (c <= JSON_TEXT('f'))));
10
}
11
 
12
bool JSONValidator::isValidNumber(const json_char * & ptr) json_nothrow {
13
    //ptr points at the first character in the number
14
    //ptr will end up past the last character
15
    bool decimal = false;
16
    bool scientific = false;
17
 
18
    //first letter is weird
19
    switch(*ptr){
20
	   #ifndef JSON_STRICT
21
		  case JSON_TEXT('.'):
22
			 decimal = true;
23
			 break;
24
		  case JSON_TEXT('+'):
25
	   #endif
26
	   case JSON_TEXT('-'):
27
		#ifdef JSON_STRICT
28
			switch(*(ptr + 1)){
29
				case '.':
30
				case 'e':
31
				case 'E':
32
				case '\0':
33
					return false;
34
			}
35
			break;
36
		#endif
37
	   case JSON_TEXT('1'):
38
	   case JSON_TEXT('2'):
39
	   case JSON_TEXT('3'):
40
	   case JSON_TEXT('4'):
41
	   case JSON_TEXT('5'):
42
	   case JSON_TEXT('6'):
43
	   case JSON_TEXT('7'):
44
	   case JSON_TEXT('8'):
45
	   case JSON_TEXT('9'):
46
		  break;
47
	   case JSON_TEXT('0'):
48
		  ++ptr;
49
		  switch(*ptr){
50
			 case JSON_TEXT('.'):
51
				decimal = true;
52
				break;
53
			 case JSON_TEXT('e'):
54
			 case JSON_TEXT('E'):
55
				scientific = true;
56
				++ptr;
57
				switch(*ptr){
58
				    case JSON_TEXT('\0'):
59
					   return false;
60
				    case JSON_TEXT('-'):
61
				    case JSON_TEXT('+'):
62
				    case JSON_TEXT('0'):
63
				    case JSON_TEXT('1'):
64
				    case JSON_TEXT('2'):
65
				    case JSON_TEXT('3'):
66
				    case JSON_TEXT('4'):
67
				    case JSON_TEXT('5'):
68
				    case JSON_TEXT('6'):
69
				    case JSON_TEXT('7'):
70
				    case JSON_TEXT('8'):
71
				    case JSON_TEXT('9'):
72
					   break;
73
				    default:
74
					   return false;
75
				}
76
				break;
77
			 #ifndef JSON_STRICT
78
				case JSON_TEXT('x'):
79
				    while(isHex(*++ptr)){};
80
				    return true;
81
				#ifdef JSON_OCTAL
82
				    //#ifdef __GNUC__
83
				    //case JSON_TEXT('0') ... JSON_TEXT('7'):  //octal
84
				    //#else
85
				    case JSON_TEXT('0'):
86
				    case JSON_TEXT('1'):
87
				    case JSON_TEXT('2'):
88
				    case JSON_TEXT('3'):
89
				    case JSON_TEXT('4'):
90
				    case JSON_TEXT('5'):
91
				    case JSON_TEXT('6'):
92
				    case JSON_TEXT('7'):
93
				    //#endif
94
					   while((*++ptr >= JSON_TEXT('0')) && (*ptr <= JSON_TEXT('7'))){};
95
					   return ((*ptr != JSON_TEXT('8')) && (*ptr != JSON_TEXT('9')));
96
				    case JSON_TEXT('8'):
97
				    case JSON_TEXT('9'):
98
					   break;
99
				#else
100
				    //#ifdef __GNUC__
101
				//	   case JSON_TEXT('0') ... JSON_TEXT('9'):
102
				    //#else
103
					   case JSON_TEXT('0'):
104
					   case JSON_TEXT('1'):
105
					   case JSON_TEXT('2'):
106
					   case JSON_TEXT('3'):
107
					   case JSON_TEXT('4'):
108
					   case JSON_TEXT('5'):
109
					   case JSON_TEXT('6'):
110
					   case JSON_TEXT('7'):
111
					   case JSON_TEXT('8'):
112
					   case JSON_TEXT('9'):
113
				    //#endif
114
				    break;
115
				#endif
116
			 #else
117
				//#ifdef __GNUC__
118
				//    case JSON_TEXT('0') ... JSON_TEXT('9'):
119
				//#else
120
				    case JSON_TEXT('0'):
121
				    case JSON_TEXT('1'):
122
				    case JSON_TEXT('2'):
123
				    case JSON_TEXT('3'):
124
				    case JSON_TEXT('4'):
125
				    case JSON_TEXT('5'):
126
				    case JSON_TEXT('6'):
127
				    case JSON_TEXT('7'):
128
				    case JSON_TEXT('8'):
129
				    case JSON_TEXT('9'):
130
				//#endif
131
				    break;
132
			 #endif
133
			 default:  //just a 0
134
				return true;
135
		  }
136
		  break;
137
	   default:
138
		  return false;
139
    }
140
    ++ptr;
141
 
142
    //next digits
143
    while (true){
144
	   switch(*ptr){
145
		  case JSON_TEXT('.'):
146
			 if (json_unlikely(decimal)) return false; //multiple decimals
147
			 if (json_unlikely(scientific)) return false;
148
			 decimal = true;
149
			 break;
150
		  case JSON_TEXT('e'):
151
		  case JSON_TEXT('E'):
152
			 if (json_likely(scientific)) return false;
153
			 scientific = true;
154
			 ++ptr;
155
			 switch(*ptr){
156
				case JSON_TEXT('-'):
157
				case JSON_TEXT('+'):
158
				//#ifdef __GNUC__
159
				//    case JSON_TEXT('0') ... JSON_TEXT('9'):
160
				//#else
161
				    case JSON_TEXT('0'):
162
				    case JSON_TEXT('1'):
163
				    case JSON_TEXT('2'):
164
				    case JSON_TEXT('3'):
165
				    case JSON_TEXT('4'):
166
				    case JSON_TEXT('5'):
167
				    case JSON_TEXT('6'):
168
				    case JSON_TEXT('7'):
169
				    case JSON_TEXT('8'):
170
				    case JSON_TEXT('9'):
171
				//#endif
172
				    break;
173
				default:
174
				    return false;
175
			 }
176
			 break;
177
		  //#ifdef __GNUC__
178
			 //case JSON_TEXT('0') ... JSON_TEXT('9'):
179
		  //#else
180
			 case JSON_TEXT('0'):
181
			 case JSON_TEXT('1'):
182
			 case JSON_TEXT('2'):
183
			 case JSON_TEXT('3'):
184
			 case JSON_TEXT('4'):
185
			 case JSON_TEXT('5'):
186
			 case JSON_TEXT('6'):
187
			 case JSON_TEXT('7'):
188
			 case JSON_TEXT('8'):
189
			 case JSON_TEXT('9'):
190
		  //#endif
191
			 break;
192
		  default:
193
			 return true;
194
	   }
195
	   ++ptr;
196
    }
197
    return false;
198
}
199
 
200
#ifndef JSON_STRICT
201
    #define LETTERCASE(x, y)\
202
	   case JSON_TEXT(x):\
203
	   case JSON_TEXT(y)
204
    #define LETTERCHECK(x, y)\
205
	   if (json_unlikely((*++ptr != JSON_TEXT(x)) && (*ptr != JSON_TEXT(y)))) return false
206
#else
207
    #define LETTERCASE(x, y)\
208
	   case JSON_TEXT(x)
209
    #define LETTERCHECK(x, y)\
210
	   if (json_unlikely(*++ptr != JSON_TEXT(x))) return false
211
#endif
212
bool JSONValidator::isValidMember(const json_char * & ptr  DEPTH_PARAM) json_nothrow {
213
    //ptr is on the first character of the member
214
    //ptr will end up immediately after the last character in the member
215
    switch(*ptr){
216
	   case JSON_TEXT('\"'):
217
		  return isValidString(++ptr);
218
	   case JSON_TEXT('{'):
219
		  INC_DEPTH();
220
		  return isValidObject(++ptr  DEPTH_ARG(depth_param));
221
	   case JSON_TEXT('['):
222
		  INC_DEPTH();
223
		  return isValidArray(++ptr  DEPTH_ARG(depth_param));
224
	   LETTERCASE('t', 'T'):
225
		  LETTERCHECK('r', 'R');
226
		  LETTERCHECK('u', 'U');
227
		  LETTERCHECK('e', 'E');
228
		  ++ptr;
229
		  return true;
230
	   LETTERCASE('f', 'F'):
231
		  LETTERCHECK('a', 'A');
232
		  LETTERCHECK('l', 'L');
233
		  LETTERCHECK('s', 'S');
234
		  LETTERCHECK('e', 'E');
235
		  ++ptr;
236
		  return true;
237
	   LETTERCASE('n', 'N'):
238
		  LETTERCHECK('u', 'U');
239
		  LETTERCHECK('l', 'L');
240
		  LETTERCHECK('l', 'L');
241
		  ++ptr;
242
		  return true;
243
	   #ifndef JSON_STRICT
244
		  case JSON_TEXT('}'):  //null in libjson
245
		  case JSON_TEXT(']'):  //null in libjson
246
		  case JSON_TEXT(','):  //null in libjson
247
			 return true;
248
	   #endif
249
	   case JSON_TEXT('\0'):
250
		  return false;
251
    }
252
    //a number
253
    return isValidNumber(ptr);
254
}
255
 
256
bool JSONValidator::isValidString(const json_char * & ptr) json_nothrow {
257
    //ptr is pointing to the first character after the quote
258
    //ptr will end up behind the closing "
259
    while(true){
260
	   switch(*ptr){
261
		  case JSON_TEXT('\\'):
262
			 switch(*(++ptr)){
263
				case JSON_TEXT('\"'):
264
				case JSON_TEXT('\\'):
265
				case JSON_TEXT('/'):
266
				case JSON_TEXT('b'):
267
				case JSON_TEXT('f'):
268
				case JSON_TEXT('n'):
269
				case JSON_TEXT('r'):
270
				case JSON_TEXT('t'):
271
				    break;
272
				case JSON_TEXT('u'):
273
				    if (json_unlikely(!isHex(*++ptr))) return false;
274
				    if (json_unlikely(!isHex(*++ptr))) return false;
275
				    //fallthrough to \x
276
				#ifndef JSON_STRICT
277
				case JSON_TEXT('x'):  //hex
278
				#endif
279
				    if (json_unlikely(!isHex(*++ptr))) return false;
280
				    if (json_unlikely(!isHex(*++ptr))) return false;
281
				    break;
282
				#ifdef JSON_OCTAL
283
				    #ifdef __GNUC__
284
				    case JSON_TEXT('0') ... JSON_TEXT('7'):  //octal
285
				    #else
286
				    case JSON_TEXT('0'):
287
				    case JSON_TEXT('1'):
288
				    case JSON_TEXT('2'):
289
				    case JSON_TEXT('3'):
290
				    case JSON_TEXT('4'):
291
				    case JSON_TEXT('5'):
292
				    case JSON_TEXT('6'):
293
				    case JSON_TEXT('7'):
294
				    #endif
295
					   if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) return false;
296
					   if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) return false;
297
					   break;
298
				#endif
299
				default:
300
				    return false;
301
			 }
302
			 break;
303
		  case JSON_TEXT('\"'):
304
			 ++ptr;
305
			 return true;
306
		  case JSON_TEXT('\0'):
307
			 return false;
308
	   }
309
	   ++ptr;
310
    }
311
    return false;
312
}
313
 
314
bool JSONValidator::isValidNamedObject(const json_char * &ptr  DEPTH_PARAM) json_nothrow {
315
    if (json_unlikely(!isValidString(++ptr))) return false;
316
    if (json_unlikely(*ptr++ != JSON_TEXT(':'))) return false;
317
    if (json_unlikely(!isValidMember(ptr  DEPTH_ARG(depth_param)))) return false;
318
    switch(*ptr){
319
	   case JSON_TEXT(','):
320
		  return isValidNamedObject(++ptr  DEPTH_ARG(depth_param));
321
	   case JSON_TEXT('}'):
322
		  ++ptr;
323
		  return true;
324
	   default:
325
		  return false;
326
    }
327
}
328
 
329
bool JSONValidator::isValidObject(const json_char * & ptr  DEPTH_PARAM) json_nothrow {
330
    //ptr should currently be pointing past the {, so this must be the start of a name, or the closing }
331
    //ptr will end up past the last }
332
    do{
333
	   switch(*ptr){
334
		  case JSON_TEXT('\"'):
335
			 return isValidNamedObject(ptr  DEPTH_ARG(depth_param));
336
		  case JSON_TEXT('}'):
337
			 ++ptr;
338
			 return true;
339
		  default:
340
			 return false;
341
	   }
342
    } while (*++ptr);
343
    return false;
344
}
345
 
346
bool JSONValidator::isValidArray(const json_char * & ptr  DEPTH_PARAM) json_nothrow {
347
    //ptr should currently be pointing past the [, so this must be the start of a member, or the closing ]
348
    //ptr will end up past the last ]
349
    do{
350
	   switch(*ptr){
351
		  case JSON_TEXT(']'):
352
			 ++ptr;
353
			 return true;
354
		  default:
355
			 if (json_unlikely(!isValidMember(ptr  DEPTH_ARG(depth_param)))) return false;
356
			 switch(*ptr){
357
				case JSON_TEXT(','):
358
				    break;
359
				case JSON_TEXT(']'):
360
				    ++ptr;
361
				    return true;
362
				default:
363
				    return false;
364
			 }
365
			 break;
366
	   }
367
    } while (*++ptr);
368
    return false;
369
}
370
 
371
bool JSONValidator::isValidRoot(const json_char * json) json_nothrow {
372
    const json_char * ptr = json;
373
    switch(*ptr){
374
	   case JSON_TEXT('{'):
375
		  if (json_likely(isValidObject(++ptr  DEPTH_ARG(1)))){
376
			 return *ptr == JSON_TEXT('\0');
377
		  }
378
		  return false;
379
	   case JSON_TEXT('['):
380
		  if (json_likely(isValidArray(++ptr  DEPTH_ARG(1)))){
381
			 return *ptr == JSON_TEXT('\0');
382
		  }
383
		  return false;
384
    }
385
    return false;
386
}
387
 
388
#ifdef JSON_STREAM
389
//It has already been checked for a complete structure, so we know it's not complete
390
bool JSONValidator::isValidPartialRoot(const json_char * json) json_nothrow {
391
	const json_char * ptr = json;
392
    switch(*ptr){
393
		case JSON_TEXT('{'):
394
		    JSON_ASSERT_SAFE(!isValidObject(++ptr  DEPTH_ARG(1)), JSON_TEXT("Partial Object seems to be valid"), {});
395
			return *ptr == JSON_TEXT('\0');
396
		case JSON_TEXT('['):
397
		    JSON_ASSERT_SAFE(!isValidArray(++ptr  DEPTH_ARG(1)), JSON_TEXT("Partial Object seems to be valid"), {});
398
			return *ptr == JSON_TEXT('\0');
399
    }
400
    return false;
401
}
402
#endif
403
 
404
#endif