The R Project SVN R-packages

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7747 ripley 1
/*
2
 *  JSONPreparse.cpp
3
 *  TestSuite
4
 *
5
 *  Created by Wallace on 4/13/11.
6
 *  Copyright 2011 Streamwide. All rights reserved.
7
 *
8
 */
9
 
10
#include "JSONPreparse.h"
11
 
12
#if (defined(JSON_PREPARSE) && defined(JSON_READ_PRIORITY))
13
 
14
#ifdef JSON_COMMENTS
15
	json_string extractComment(json_string::const_iterator & ptr, json_string::const_iterator & end);
16
	json_string extractComment(json_string::const_iterator & ptr, json_string::const_iterator & end){
17
		json_string::const_iterator start;
18
		json_string result;
19
looplabel:
20
		if (json_unlikely(((ptr != end) && (*ptr == JSON_TEMP_COMMENT_IDENTIFIER)))){
21
			start = ++ptr;
22
			for(; (ptr != end) && (*(ptr) != JSON_TEMP_COMMENT_IDENTIFIER); ++ptr){}
23
			result += json_string(start, ptr);
24
			if (json_unlikely(ptr == end)) return result;
25
			++ptr;
26
			if (json_unlikely(((ptr != end) && (*ptr == JSON_TEMP_COMMENT_IDENTIFIER)))){
27
				result += JSON_TEXT('\n');
28
				goto looplabel;
29
			}
30
		}
31
		return result;
32
	}
33
	#define GET_COMMENT(x, y, name) json_string name = extractComment(x, y)
34
	#define RETURN_NODE(node, name){\
35
		JSONNode res = node;\
36
		res.set_comment(name);\
37
		return res;\
38
	}
39
	#define RETURN_NODE_NOCOPY(node, name){\
40
		node.set_comment(name);\
41
		return node;\
42
	}
43
	#define SET_COMMENT(node, name) node.set_comment(name)
44
	#define COMMENT_ARG(name) ,name
45
#else
46
	#define GET_COMMENT(x, y, name) (void)0
47
	#define RETURN_NODE(node, name) return node
48
	#define RETURN_NODE_NOCOPY(node, name) return node
49
	#define SET_COMMENT(node, name) (void)0
50
	#define COMMENT_ARG(name)
51
#endif
52
 
53
inline bool isHex(json_char c) json_pure;
54
inline bool isHex(json_char c) json_nothrow {
55
    return (((c >= JSON_TEXT('0')) && (c <= JSON_TEXT('9'))) ||
56
		  ((c >= JSON_TEXT('A')) && (c <= JSON_TEXT('F'))) ||
57
		  ((c >= JSON_TEXT('a')) && (c <= JSON_TEXT('f'))));
58
}
59
 
60
#ifdef JSON_STRICT
61
	#include "NumberToString.h"
62
#endif
63
 
64
json_number FetchNumber(const json_string & _string) json_nothrow;
65
json_number FetchNumber(const json_string & _string) json_nothrow {
66
    #ifdef JSON_STRICT
67
	   return NumberToString::_atof(_string.c_str());
68
    #else
69
	   #ifdef JSON_UNICODE
70
		  const size_t len = _string.length();
71
		  #if defined(_MSC_VER) && defined(JSON_SAFE)
72
			 const size_t bytes = (len * (sizeof(json_char) / sizeof(char))) + 1;
73
			 json_auto<char> temp(bytes);
74
			 size_t res;
75
			 errno_t err = std::wcstombs_s(&res, temp.ptr, bytes, _string.c_str(), len);
76
			 if (err != 0){
77
				return (json_number)0.0;
78
			 }
79
		  #elif defined(JSON_SAFE)
80
			 const size_t bytes = (len * (sizeof(json_char) / sizeof(char))) + 1;
81
			 json_auto<char> temp(bytes);
82
			 size_t res = std::wcstombs(temp.ptr, _string.c_str(), len);
83
			 if (res == (size_t)-1){  //-1 is error code for this function
84
				return (json_number)0.0;
85
			 }
86
		  #else
87
			 json_auto<char> temp(len + 1);
88
			 size_t res = std::wcstombs(temp.ptr, _string.c_str(), len);
89
		  #endif
90
		  temp.ptr[res] = JSON_TEXT('\0');
91
		  return (json_number)std::atof(temp.ptr);
92
	   #else
93
		  return (json_number)std::atof(_string.c_str());
94
	   #endif
95
    #endif
96
}
97
 
98
JSONNode JSONPreparse::isValidNumber(json_string::const_iterator & ptr, json_string::const_iterator & end){
99
    //ptr points at the first character in the number
100
    //ptr will end up past the last character
101
    json_string::const_iterator start = ptr;
102
    bool decimal = false;
103
    bool scientific = false;
104
 
105
    //first letter is weird
106
    switch(*ptr){
107
	   #ifndef JSON_STRICT
108
	   case JSON_TEXT('.'):
109
		  decimal = true;
110
		  break;
111
	   case JSON_TEXT('+'):
112
	   #endif
113
 
114
	   case JSON_TEXT('-'):
115
	   case JSON_TEXT('1'):
116
	   case JSON_TEXT('2'):
117
	   case JSON_TEXT('3'):
118
	   case JSON_TEXT('4'):
119
	   case JSON_TEXT('5'):
120
	   case JSON_TEXT('6'):
121
	   case JSON_TEXT('7'):
122
	   case JSON_TEXT('8'):
123
	   case JSON_TEXT('9'):
124
		  break;
125
	   case JSON_TEXT('0'):
126
		  ++ptr;
127
		  switch(*ptr){
128
			 case JSON_TEXT('.'):
129
				decimal = true;
130
				break;
131
			 case JSON_TEXT('e'):
132
			 case JSON_TEXT('E'):
133
				scientific = true;
134
				++ptr;
135
				if (ptr == end) throw false;
136
				switch(*ptr){
137
				    case JSON_TEXT('-'):
138
				    case JSON_TEXT('+'):
139
				    case JSON_TEXT('0'):
140
				    case JSON_TEXT('1'):
141
				    case JSON_TEXT('2'):
142
				    case JSON_TEXT('3'):
143
				    case JSON_TEXT('4'):
144
				    case JSON_TEXT('5'):
145
				    case JSON_TEXT('6'):
146
				    case JSON_TEXT('7'):
147
				    case JSON_TEXT('8'):
148
				    case JSON_TEXT('9'):
149
					   break;
150
				    default:
151
					   throw false;
152
				}
153
				break;
154
 
155
			 #ifndef JSON_STRICT
156
			 case JSON_TEXT('x'):
157
				while(isHex(*++ptr)){};
158
				return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, end - 1)));
159
			 #ifdef JSON_OCTAL
160
			 #ifdef __GNUC__
161
				case JSON_TEXT('0') ... JSON_TEXT('7'):  //octal
162
			 #else
163
				case JSON_TEXT('0'):
164
				case JSON_TEXT('1'):
165
				case JSON_TEXT('2'):
166
				case JSON_TEXT('3'):
167
				case JSON_TEXT('4'):
168
				case JSON_TEXT('5'):
169
				case JSON_TEXT('6'):
170
				case JSON_TEXT('7'):
171
			 #endif
172
				while((*++ptr >= JSON_TEXT('0')) && (*ptr <= JSON_TEXT('7'))){};
173
				if ((*ptr != JSON_TEXT('8')) && (*ptr != JSON_TEXT('9'))){
174
				    return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, ptr - 1)));
175
				} 
176
				throw false;
177
			 case JSON_TEXT('8'):
178
			 case JSON_TEXT('9'):
179
				break;
180
			 #else
181
			 #ifdef __GNUC__
182
				case JSON_TEXT('0') ... JSON_TEXT('9'):
183
			 #else
184
				case JSON_TEXT('0'):
185
				case JSON_TEXT('1'):
186
				case JSON_TEXT('2'):
187
				case JSON_TEXT('3'):
188
				case JSON_TEXT('4'):
189
				case JSON_TEXT('5'):
190
				case JSON_TEXT('6'):
191
				case JSON_TEXT('7'):
192
				case JSON_TEXT('8'):
193
				case JSON_TEXT('9'):
194
			 #endif
195
				break;
196
			 #endif
197
			 #else
198
			 #ifdef __GNUC__
199
				case JSON_TEXT('0') ... JSON_TEXT('9'):
200
			 #else
201
				case JSON_TEXT('0'):
202
				case JSON_TEXT('1'):
203
				case JSON_TEXT('2'):
204
				case JSON_TEXT('3'):
205
				case JSON_TEXT('4'):
206
				case JSON_TEXT('5'):
207
				case JSON_TEXT('6'):
208
				case JSON_TEXT('7'):
209
				case JSON_TEXT('8'):
210
				case JSON_TEXT('9'):
211
			 #endif
212
				break;
213
			 #endif
214
			 default:  //just a 0
215
				return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, ptr - 1)));;
216
		  }
217
		  break;
218
	   default:
219
		  throw false;
220
    }
221
    ++ptr;
222
 
223
    //next digits
224
    while (true){
225
	   switch(*ptr){
226
		  case JSON_TEXT('.'):
227
			 if (json_unlikely(decimal)) throw false; //multiple decimals
228
			 if (json_unlikely(scientific)) throw false;
229
			 decimal = true;
230
			 break;
231
		  case JSON_TEXT('e'):
232
		  case JSON_TEXT('E'):
233
			 if (json_likely(scientific)) throw false;
234
			 scientific = true;
235
			 ++ptr;
236
			 switch(*ptr){
237
				case JSON_TEXT('-'):
238
				case JSON_TEXT('+'):
239
				#ifdef __GNUC__
240
				case JSON_TEXT('0') ... JSON_TEXT('9'):
241
				#else
242
				case JSON_TEXT('0'):
243
				case JSON_TEXT('1'):
244
				case JSON_TEXT('2'):
245
				case JSON_TEXT('3'):
246
				case JSON_TEXT('4'):
247
				case JSON_TEXT('5'):
248
				case JSON_TEXT('6'):
249
				case JSON_TEXT('7'):
250
				case JSON_TEXT('8'):
251
				case JSON_TEXT('9'):
252
				#endif
253
				    break;
254
				default:
255
				    throw false;
256
			 }
257
			 break;
258
		  #ifdef __GNUC__
259
		  case JSON_TEXT('0') ... JSON_TEXT('9'):
260
		  #else
261
		  case JSON_TEXT('0'):
262
		  case JSON_TEXT('1'):
263
		  case JSON_TEXT('2'):
264
		  case JSON_TEXT('3'):
265
		  case JSON_TEXT('4'):
266
		  case JSON_TEXT('5'):
267
		  case JSON_TEXT('6'):
268
		  case JSON_TEXT('7'):
269
		  case JSON_TEXT('8'):
270
		  case JSON_TEXT('9'):
271
		  #endif
272
			 break;
273
		  default:
274
			 return JSONNode(json_global(EMPTY_JSON_STRING), FetchNumber(json_string(start, ptr)));;
275
	   }
276
	   ++ptr;
277
    }
278
    throw false;
279
}
280
 
281
#ifndef JSON_STRICT
282
    #define LETTERCASE(x, y)\
283
	   case JSON_TEXT(x):\
284
	   case JSON_TEXT(y)
285
    #define LETTERCHECK(x, y)\
286
	   if (json_unlikely((*++ptr != JSON_TEXT(x)) && (*ptr != JSON_TEXT(y)))) throw false
287
#else
288
    #define LETTERCASE(x, y)\
289
	   case JSON_TEXT(x)
290
    #define LETTERCHECK(x, y)\
291
	   if (json_unlikely(*++ptr != JSON_TEXT(x))) throw false
292
#endif
293
JSONNode JSONPreparse::isValidMember(json_string::const_iterator & ptr, json_string::const_iterator & end){
294
    //ptr is on the first character of the member
295
    //ptr will end up immediately after the last character in the member
296
    if (ptr == end) throw false;
297
 
298
    switch(*ptr){
299
	   case JSON_TEXT('\"'):{
300
           return JSONNode::stringType(isValidString(++ptr, end));
301
	   }
302
	   case JSON_TEXT('{'):
303
		  return isValidObject(++ptr, end);
304
	   case JSON_TEXT('['):
305
		  return isValidArray(++ptr, end);
306
	   LETTERCASE('t', 'T'):
307
	   LETTERCHECK('r', 'R');
308
	   LETTERCHECK('u', 'U');
309
	   LETTERCHECK('e', 'E');
310
		  ++ptr;
311
		  return JSONNode(json_global(EMPTY_JSON_STRING), true);
312
	   LETTERCASE('f', 'F'):
313
	   LETTERCHECK('a', 'A');
314
	   LETTERCHECK('l', 'L');
315
	   LETTERCHECK('s', 'S');
316
	   LETTERCHECK('e', 'E');
317
		  ++ptr;
318
		  return JSONNode(json_global(EMPTY_JSON_STRING), false);
319
	   LETTERCASE('n', 'N'):
320
	   LETTERCHECK('u', 'U');
321
	   LETTERCHECK('l', 'L');
322
	   LETTERCHECK('l', 'L');
323
		  ++ptr;
324
		  return JSONNode(JSON_NULL);
325
	   #ifndef JSON_STRICT
326
		  case JSON_TEXT('}'):  //null in libjson
327
		  case JSON_TEXT(']'):  //null in libjson
328
		  case JSON_TEXT(','):  //null in libjson
329
			 return JSONNode(JSON_NULL);
330
	   #endif
331
    }
332
    //a number
333
    return isValidNumber(ptr, end);
334
}
335
 
336
json_string JSONPreparse::isValidString(json_string::const_iterator & ptr, json_string::const_iterator & end){
337
    //ptr is pointing to the first character after the quote
338
    //ptr will end up behind the closing "
339
    json_string::const_iterator start = ptr;
340
 
341
    while(ptr != end){
342
	   switch(*ptr){
343
		  case JSON_TEXT('\\'):
344
			 switch(*(++ptr)){
345
				case JSON_TEXT('\"'):
346
				case JSON_TEXT('\\'):
347
				case JSON_TEXT('/'):
348
				case JSON_TEXT('b'):
349
				case JSON_TEXT('f'):
350
				case JSON_TEXT('n'):
351
				case JSON_TEXT('r'):
352
				case JSON_TEXT('t'):
353
				    break;
354
				case JSON_TEXT('u'):
355
				    if (json_unlikely(!isHex(*++ptr))) throw false;
356
				    if (json_unlikely(!isHex(*++ptr))) throw false;
357
				    //fallthrough to \x
358
				#ifndef JSON_STRICT
359
				    case JSON_TEXT('x'):  //hex
360
				#endif
361
				    if (json_unlikely(!isHex(*++ptr))) throw false;
362
				    if (json_unlikely(!isHex(*++ptr))) throw false;
363
				    break;
364
				#ifndef JSON_OCTAL
365
				    #ifdef __GNUC__
366
					   case JSON_TEXT('0') ... JSON_TEXT('7'):  //octal
367
				    #else
368
					   case JSON_TEXT('0'):
369
					   case JSON_TEXT('1'):
370
					   case JSON_TEXT('2'):
371
					   case JSON_TEXT('3'):
372
					   case JSON_TEXT('4'):
373
					   case JSON_TEXT('5'):
374
					   case JSON_TEXT('6'):
375
					   case JSON_TEXT('7'):
376
				    #endif
377
				    if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) throw false;
378
				    if (json_unlikely((*++ptr < JSON_TEXT('0')) || (*ptr > JSON_TEXT('7')))) throw false;
379
				    break;
380
				#endif
381
				default:
382
				    throw false;
383
			 }
384
			 break;
385
		  case JSON_TEXT('\"'):
386
			 return json_string(start, ptr++);
387
	   }
388
	   ++ptr;
389
    }
390
    throw false;
391
}
392
 
393
void JSONPreparse::isValidNamedObject(json_string::const_iterator & ptr, json_string::const_iterator & end, JSONNode & parent COMMENT_PARAM(comment)) {
394
	//ptr should be right before the string name
395
    {
396
	   json_string _name = isValidString(++ptr, end);
397
	   if (json_unlikely(*ptr++ != JSON_TEXT(':'))) throw false;
398
	   JSONNode res = isValidMember(ptr, end);
399
	   res.set_name_(_name);
400
		SET_COMMENT(res, comment);
401
		#ifdef JSON_LIBRARY
402
			parent.push_back(&res);
403
		#else
404
			parent.push_back(res);
405
		#endif
406
    }
407
    if (ptr == end) throw false;
408
    switch(*ptr){
409
	   case JSON_TEXT(','):
410
			++ptr;
411
			{
412
				GET_COMMENT(ptr, end, nextcomment);
413
				isValidNamedObject(ptr, end, parent COMMENT_ARG(nextcomment));  //will handle all of them
414
			}
415
			return;
416
	   case JSON_TEXT('}'):
417
		  ++ptr;
418
		  return;
419
	   default:
420
		  throw false;
421
    }
422
}
423
 
424
JSONNode JSONPreparse::isValidObject(json_string::const_iterator & ptr, json_string::const_iterator & end) {
425
    //ptr should currently be pointing past the {, so this must be the start of a name, or the closing }
426
    //ptr will end up past the last }
427
    JSONNode res(JSON_NODE);
428
	GET_COMMENT(ptr, end, comment);
429
	switch(*ptr){
430
	  case JSON_TEXT('\"'):
431
		 isValidNamedObject(ptr, end, res COMMENT_ARG(comment));
432
		 return res;
433
	  case JSON_TEXT('}'):
434
		 ++ptr;
435
		 return res;
436
	  default:
437
		 throw false;
438
	}
439
}
440
 
441
void pushArrayMember(JSONNode & res, json_string::const_iterator & ptr, json_string::const_iterator & end);
442
void pushArrayMember(JSONNode & res, json_string::const_iterator & ptr, json_string::const_iterator & end){
443
	GET_COMMENT(ptr, end, comment);
444
	JSONNode temp = JSONPreparse::isValidMember(ptr, end);
445
	SET_COMMENT(temp, comment);
446
	#ifdef JSON_LIBRARY
447
		res.push_back(&temp);
448
	#else
449
		res.push_back(temp);
450
	#endif
451
}
452
 
453
JSONNode JSONPreparse::isValidArray(json_string::const_iterator & ptr, json_string::const_iterator & end) {
454
    //ptr should currently be pointing past the [, so this must be the start of a member, or the closing ]
455
    //ptr will end up past the last ]
456
    JSONNode res(JSON_ARRAY);
457
    do{
458
	   switch(*ptr){
459
		  case JSON_TEXT(']'):
460
			 ++ptr;
461
			   return res;
462
		  default:
463
			 pushArrayMember(res, ptr, end);
464
			 switch(*ptr){
465
				case JSON_TEXT(','):
466
				    break;
467
				case JSON_TEXT(']'):
468
				    ++ptr;
469
					return res;
470
				default:
471
				    throw false;
472
			 }
473
			 break;
474
	   }
475
    } while (++ptr != end);
476
    throw false;
477
}
478
 
479
JSONNode JSONPreparse::isValidRoot(const json_string & json) json_throws(std::invalid_argument) {
480
    json_string::const_iterator it = json.begin();
481
    json_string::const_iterator end = json.end();
482
    try {
483
		GET_COMMENT(it, end, comment);
484
	   switch(*it){
485
		  case JSON_TEXT('{'):
486
			   RETURN_NODE(isValidObject(++it, end), comment);
487
		   case JSON_TEXT('['):
488
			   RETURN_NODE(isValidArray(++it, end), comment);
489
	   }
490
    } catch (...){}
491
 
492
    #ifndef JSON_NO_EXCEPTIONS
493
	   throw std::invalid_argument(json_global(EMPTY_STD_STRING));
494
    #else
495
	   return JSONNode(JSON_NULL);
496
    #endif
497
}
498
 
499
#endif