]> git.armaanb.net Git - gen-shell.git/blob - src/libshared/src/SAX.cpp
added install instructions
[gen-shell.git] / src / libshared / src / SAX.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2006 - 2017, Paul Beckingham, Federico Hernandez.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 // http://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26
27 #include <cmake.h>
28 #include <JSON.h>
29 #include <utf8.h>
30 #include <sstream>
31 #include <stdlib.h>
32 #include <inttypes.h>
33 #include <errno.h>
34
35 ////////////////////////////////////////////////////////////////////////////////
36 bool json::SAX::parse (const std::string& input, SAX::Sink& sink)
37 {
38   sink.eventDocStart ();
39   std::string::size_type cursor = 0;
40   ignoreWhitespace (input, cursor);
41   if (isObject (input, cursor, sink) ||
42       isArray  (input, cursor, sink))
43   {
44     ignoreWhitespace (input, cursor);
45     if (cursor < input.length ())
46       error ("Error: extra characters found at position ", cursor);
47
48     sink.eventDocEnd ();
49     return true;
50   }
51
52   error ("Error: Missing '{' or '[' at position ", cursor);
53   return false;
54 }
55
56 ////////////////////////////////////////////////////////////////////////////////
57 // Complete Unicode whitespace list.
58 //
59 // http://en.wikipedia.org/wiki/Whitespace_character
60 // Updated 2015-09-13
61 void json::SAX::ignoreWhitespace (const std::string& input, std::string::size_type& cursor)
62 {
63   int c = input[cursor];
64   while (c == 0x0020 ||   // space Common  Separator, space
65          c == 0x0009 ||   // Common  Other, control  HT, Horizontal Tab
66          c == 0x000A ||   // Common  Other, control  LF, Line feed
67          c == 0x000B ||   // Common  Other, control  VT, Vertical Tab
68          c == 0x000C ||   // Common  Other, control  FF, Form feed
69          c == 0x000D ||   // Common  Other, control  CR, Carriage return
70          c == 0x0085 ||   // Common  Other, control  NEL, Next line
71          c == 0x00A0 ||   // no-break space  Common  Separator, space
72          c == 0x1680 ||   // ogham space mark  Ogham Separator, space
73          c == 0x180E ||   // mongolian vowel separator Mongolian Separator, space
74          c == 0x2000 ||   // en quad Common  Separator, space
75          c == 0x2001 ||   // em quad Common  Separator, space
76          c == 0x2002 ||   // en space  Common  Separator, space
77          c == 0x2003 ||   // em space  Common  Separator, space
78          c == 0x2004 ||   // three-per-em space  Common  Separator, space
79          c == 0x2005 ||   // four-per-em space Common  Separator, space
80          c == 0x2006 ||   // six-per-em space  Common  Separator, space
81          c == 0x2007 ||   // figure space  Common  Separator, space
82          c == 0x2008 ||   // punctuation space Common  Separator, space
83          c == 0x2009 ||   // thin space  Common  Separator, space
84          c == 0x200A ||   // hair space  Common  Separator, space
85          c == 0x200B ||   // zero width space
86          c == 0x200C ||   // zero width non-joiner
87          c == 0x200D ||   // zero width joiner
88          c == 0x2028 ||   // line separator  Common  Separator, line
89          c == 0x2029 ||   // paragraph separator Common  Separator, paragraph
90          c == 0x202F ||   // narrow no-break space Common  Separator, space
91          c == 0x205F ||   // medium mathematical space Common  Separator, space
92          c == 0x2060 ||   // word joiner
93          c == 0x3000)     // ideographic space Common  Separator, space
94   {
95     c = input[++cursor];
96   }
97 }
98
99 ////////////////////////////////////////////////////////////////////////////////
100 // object := '{' [<pair> [, <pair> ...]] '}'
101 bool json::SAX::isObject (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
102 {
103   ignoreWhitespace (input, cursor);
104   auto backup = cursor;
105
106   if (isLiteral (input, '{', cursor))
107   {
108     sink.eventObjectStart ();
109     int counter = 0;
110
111     if (isPair (input, cursor, sink))
112     {
113       ++counter;
114       while (isLiteral (input, ',', cursor) &&
115              isPair    (input, cursor, sink))
116       {
117         ++counter;
118       }
119     }
120
121     ignoreWhitespace (input, cursor);
122     if (isLiteral (input, '}', cursor))
123     {
124       sink.eventObjectEnd (counter);
125       return true;
126     }
127     else
128       error ("Error: Missing '}' at position ", cursor);
129   }
130
131   cursor = backup;
132   return false;
133 }
134
135 ////////////////////////////////////////////////////////////////////////////////
136 // array := '[' [<value> [, <value> ...]] ']'
137 bool json::SAX::isArray (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
138 {
139   ignoreWhitespace (input, cursor);
140   auto backup = cursor;
141
142   if (isLiteral (input, '[', cursor))
143   {
144     sink.eventArrayStart ();
145     int counter = 0;
146
147     if (isValue (input, cursor, sink))
148     {
149       ++counter;
150       while (isLiteral (input, ',', cursor) &&
151              isValue   (input,      cursor, sink))
152       {
153         ++counter;
154       }
155     }
156
157     ignoreWhitespace (input, cursor);
158     if (isLiteral (input, ']', cursor))
159     {
160       sink.eventArrayEnd (counter);
161       return true;
162     }
163     else
164       error ("Error: Missing ']' at position ", cursor);
165   }
166
167   cursor = backup;
168   return false;
169 }
170
171 ////////////////////////////////////////////////////////////////////////////////
172 // pair := <string> ':' <value>
173 bool json::SAX::isPair (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
174 {
175   ignoreWhitespace (input, cursor);
176   auto backup = cursor;
177
178   if (isKey (input, cursor, sink))
179   {
180     if (isLiteral (input, ':', cursor))
181     {
182       if (isValue (input, cursor, sink))
183         return true;
184
185       error ("Error: Missing value at position ", cursor);
186     }
187     else
188       error ("Error: Missing ':' at position ", cursor);
189   }
190
191   cursor = backup;
192   return false;
193 }
194
195 ////////////////////////////////////////////////////////////////////////////////
196 // value  := <string>
197 //         | <number>
198 //         | <object>
199 //         | <array>
200 //         | 'true'
201 //         | 'false'
202 //         | 'null'
203 bool json::SAX::isValue (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
204 {
205   ignoreWhitespace (input, cursor);
206
207   return isString (input, cursor, sink) ||
208          isNumber (input, cursor, sink) ||
209          isObject (input, cursor, sink) ||
210          isArray  (input, cursor, sink) ||
211          isBool   (input, cursor, sink) ||
212          isNull   (input, cursor, sink);
213 }
214
215 ////////////////////////////////////////////////////////////////////////////////
216 bool json::SAX::isKey (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
217 {
218   ignoreWhitespace (input, cursor);
219
220   std::string value;
221   if (isStringValue (input, cursor, value))
222   {
223     sink.eventName (value);
224     return true;
225   }
226
227   return false;
228 }
229
230 ////////////////////////////////////////////////////////////////////////////////
231 bool json::SAX::isString (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
232 {
233   ignoreWhitespace (input, cursor);
234
235   std::string value;
236   if (isStringValue (input, cursor, value))
237   {
238     sink.eventValueString (value);
239     return true;
240   }
241
242   return false;
243 }
244
245 ////////////////////////////////////////////////////////////////////////////////
246 // string := '"' [<chars> ...] '"'
247 // chars  := <unicode>
248 //         | '\"'
249 //         | '\\'
250 //         | '\/'
251 //         | '\b'
252 //         | '\f'
253 //         | '\n'
254 //         | '\r'
255 //         | '\t'
256 //         | \uXXXX
257 bool json::SAX::isStringValue (const std::string& input, std::string::size_type& cursor, std::string& value)
258 {
259   auto backup = cursor;
260
261   if (isLiteral (input, '"', cursor))
262   {
263     std::string word;
264     int c;
265     while ((c = input[cursor]))
266     {
267       // EOS.
268       if (c == '"')
269       {
270         ++cursor;
271         value = word;
272         return true;
273       }
274
275       // Unicode \uXXXX codepoint.
276       else if (input[cursor + 0] == '\\'  &&
277                input[cursor + 1] == 'u'   &&
278                isHexDigit (input[cursor + 2]) &&
279                isHexDigit (input[cursor + 3]) &&
280                isHexDigit (input[cursor + 4]) &&
281                isHexDigit (input[cursor + 5]))
282       {
283         word += utf8_character (
284                   hexToInt (
285                     input[cursor + 2],
286                     input[cursor + 3],
287                     input[cursor + 4],
288                     input[cursor + 5]));
289         cursor += 6;
290       }
291
292       // An escaped thing.
293       else if (c == '\\')
294       {
295         c = input[++cursor];
296         switch (c)
297         {
298         case '"':  word += (char) 0x22; ++cursor; break;
299         case '\'': word += (char) 0x27; ++cursor; break;
300         case '\\': word += (char) 0x5C; ++cursor; break;
301         case 'b':  word += (char) 0x08; ++cursor; break;
302         case 'f':  word += (char) 0x0C; ++cursor; break;
303         case 'n':  word += (char) 0x0A; ++cursor; break;
304         case 'r':  word += (char) 0x0D; ++cursor; break;
305         case 't':  word += (char) 0x09; ++cursor; break;
306         case 'v':  word += (char) 0x0B; ++cursor; break;
307
308         // This pass-through default case means that anything can be escaped
309         // harmlessly. In particular 'quote' is included, if it not one of the
310         // above characters.
311         default:   word += (char) c;    ++cursor; break;
312         }
313       }
314
315       // Ordinary character.
316       else
317       {
318         word += (char) c;
319         ++cursor;
320       }
321     }
322
323     error ("Error: Missing '\"' at position ", cursor);
324   }
325
326   cursor = backup;
327   return false;
328 }
329
330 ////////////////////////////////////////////////////////////////////////////////
331 // number := <int> [<frac>] [<exp>]
332 bool json::SAX::isNumber (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
333 {
334   ignoreWhitespace (input, cursor);
335   auto backup = cursor;
336
337   std::string integerPart;
338   if (isInt (input, cursor, integerPart))
339   {
340     std::string fractionalPart;
341     isFrac (input, cursor, fractionalPart);
342
343     std::string exponentPart;
344     isExp (input, cursor, exponentPart);
345
346     // Does it fit in a long?
347     std::string combined = integerPart + fractionalPart + exponentPart;
348     char* end;
349     long longValue = strtol (combined.c_str (), &end, 10);
350     if (! *end && errno != ERANGE)
351     {
352       sink.eventValueInt (longValue);
353       return true;
354     }
355
356     // Does it fit in an unsigned long?
357     unsigned long ulongValue = strtoul (combined.c_str (), &end, 10);
358     if (! *end && errno != ERANGE)
359     {
360       sink.eventValueUint (ulongValue);
361       return true;
362     }
363
364     // If the above fail, allow this one to be capped at imax.
365     double doubleValue = strtod (combined.c_str (), &end);
366     if (! *end)
367     {
368       sink.eventValueDouble (doubleValue);
369       return true;
370     }
371   }
372
373   cursor = backup;
374   return false;
375 }
376
377 ////////////////////////////////////////////////////////////////////////////////
378 // int := ['-'] <digits>
379 bool json::SAX::isInt (const std::string& input, std::string::size_type& cursor, std::string& value)
380 {
381   auto backup = cursor;
382
383   isLiteral (input, '-', cursor);
384   if (isDigits (input, cursor))
385   {
386     value = input.substr (backup, cursor - backup);
387     return true;
388   }
389
390   // No restore necessary.
391   return false;
392 }
393
394 ////////////////////////////////////////////////////////////////////////////////
395 // frac := '.' <digits>
396 bool json::SAX::isFrac (const std::string& input, std::string::size_type& cursor, std::string& value)
397 {
398   auto backup = cursor;
399
400   if (isLiteral (input, '.', cursor) &&
401       isDigits  (input,      cursor))
402   {
403     value = input.substr (backup, cursor - backup);
404     return true;
405   }
406
407   cursor = backup;
408   return false;
409 }
410
411 ////////////////////////////////////////////////////////////////////////////////
412 // digits := <digit> [<digit> ...]
413 bool json::SAX::isDigits (const std::string& input, std::string::size_type& cursor)
414 {
415   int c = input[cursor];
416   if (isDecDigit (c))
417   {
418     c = input[++cursor];
419
420     while (isDecDigit (c))
421       c = input[++cursor];
422
423     return true;
424   }
425
426   return false;
427 }
428
429 ////////////////////////////////////////////////////////////////////////////////
430 // digit := 0x30 ('0') .. 0x39 ('9')
431 bool json::SAX::isDecDigit (int c)
432 {
433   return c >= 0x30 && c <= 0x39;
434 }
435
436 ////////////////////////////////////////////////////////////////////////////////
437 // hex := 0x30 ('0') .. 0x39 ('9')
438 bool json::SAX::isHexDigit (int c)
439 {
440   return (c >= 0x30 && c <= 0x39) ||
441          (c >= 0x61 && c <= 0x66) ||
442          (c >= 0x41 && c <= 0x46);
443 }
444
445 ////////////////////////////////////////////////////////////////////////////////
446 // exp := <e> <digits>
447 bool json::SAX::isExp (const std::string& input, std::string::size_type& cursor, std::string& value)
448 {
449   auto backup = cursor;
450
451   if (isE      (input, cursor) &&
452       isDigits (input, cursor))
453   {
454     value = input.substr (backup, cursor - backup);
455     return true;
456   }
457
458   cursor = backup;
459   return false;
460 }
461
462 ////////////////////////////////////////////////////////////////////////////////
463 // e := e
464 //    | e+
465 //    | e-
466 //    | E
467 //    | E+
468 //    | E-
469 bool json::SAX::isE (const std::string& input, std::string::size_type& cursor)
470 {
471   int c = input[cursor];
472   if (c == 'e' ||
473       c == 'E')
474   {
475     c = input[++cursor];
476
477     if (c == '+' ||
478         c == '-')
479     {
480       ++cursor;
481     }
482
483     return true;
484   }
485
486   return false;
487 }
488
489 ////////////////////////////////////////////////////////////////////////////////
490 bool json::SAX::isBool (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
491 {
492   ignoreWhitespace (input, cursor);
493
494   if (input[cursor + 0] == 't' &&
495       input[cursor + 1] == 'r' &&
496       input[cursor + 2] == 'u' &&
497       input[cursor + 3] == 'e')
498   {
499     cursor += 4;
500     sink.eventValueBool (true);
501     return true;
502   }
503   else if (input[cursor + 0] == 'f' &&
504            input[cursor + 1] == 'a' &&
505            input[cursor + 2] == 'l' &&
506            input[cursor + 3] == 's' &&
507            input[cursor + 4] == 'e')
508   {
509     cursor += 5;
510     sink.eventValueBool (false);
511     return true;
512   }
513
514   return false;
515 }
516
517 ////////////////////////////////////////////////////////////////////////////////
518 bool json::SAX::isNull (const std::string& input, std::string::size_type& cursor, SAX::Sink& sink)
519 {
520   ignoreWhitespace (input, cursor);
521
522   if (input[cursor + 0] == 'n' &&
523       input[cursor + 1] == 'u' &&
524       input[cursor + 2] == 'l' &&
525       input[cursor + 3] == 'l')
526   {
527     cursor += 4;
528     sink.eventValueNull ();
529     return true;
530   }
531
532   return false;
533 }
534
535 ////////////////////////////////////////////////////////////////////////////////
536 bool json::SAX::isLiteral (const std::string& input, char literal, std::string::size_type& cursor)
537 {
538   ignoreWhitespace (input, cursor);
539
540   if (input[cursor] == literal)
541   {
542     ++cursor;
543     return true;
544   }
545
546   return false;
547 }
548
549 ////////////////////////////////////////////////////////////////////////////////
550 // Converts '0'     -> 0
551 //          '9'     -> 9
552 //          'a'/'A' -> 10
553 //          'f'/'F' -> 15
554 int json::SAX::hexToInt (int c)
555 {
556        if (c >= 0x30 && c <= 0x39) return (c - 0x30);
557   else if (c >= 0x41 && c <= 0x46) return (c - 0x41 + 10);
558   else                             return (c - 0x61 + 10);
559 }
560
561 ////////////////////////////////////////////////////////////////////////////////
562 int json::SAX::hexToInt (int c0, int c1, int c2, int c3)
563 {
564   return (hexToInt (c0) << 12) +
565          (hexToInt (c1) << 8)  +
566          (hexToInt (c2) << 4)  +
567           hexToInt (c3);
568 }
569
570 ////////////////////////////////////////////////////////////////////////////////
571 void json::SAX::error (const std::string& message, std::string::size_type cursor)
572 {
573   std::stringstream error;
574   error << message << cursor;
575   throw error.str ();
576 }
577
578 ////////////////////////////////////////////////////////////////////////////////
579