Jamoma API  0.6.0.a19
JSONValidator.cpp
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