openEventsPlatformApp/plugins/ionic-plugin-keyboard/src/blackberry10/native/public/json_reader.cpp
plugins/ionic-plugin-keyboard/src/blackberry10/native/public/json_reader.cppRaw
1#include <json/reader.h>
2#include <json/value.h>
3#include <utility>
4#include <cstdio>
5#include <cassert>
6#include <cstring>
7#include <iostream>
8#include <stdexcept>
9
10#if _MSC_VER >= 1400 // VC++ 8.0
11#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
12#endif
13
14namespace Json {
15
16// QNX is strict about declaring C symbols in the std namespace.
17#ifdef __QNXNTO__
18using std::memcpy;
19using std::sprintf;
20using std::sscanf;
21#endif
22
23// Implementation of class Features
24// ////////////////////////////////
25
26Features::Features()
27 : allowComments_( true )
28 , strictRoot_( false )
29{
30}
31
32
33Features
34Features::all()
35{
36 return Features();
37}
38
39
40Features
41Features::strictMode()
42{
43 Features features;
44 features.allowComments_ = false;
45 features.strictRoot_ = true;
46 return features;
47}
48
49// Implementation of class Reader
50// ////////////////////////////////
51
52
53static inline bool
54in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
55{
56 return c == c1 || c == c2 || c == c3 || c == c4;
57}
58
59static inline bool
60in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
61{
62 return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
63}
64
65
66static bool
67containsNewLine( Reader::Location begin,
68 Reader::Location end )
69{
70 for ( ;begin < end; ++begin )
71 if ( *begin == '\n' || *begin == '\r' )
72 return true;
73 return false;
74}
75
76static std::string codePointToUTF8(unsigned int cp)
77{
78 std::string result;
79
80 // based on description from http://en.wikipedia.org/wiki/UTF-8
81
82 if (cp <= 0x7f)
83 {
84 result.resize(1);
85 result[0] = static_cast<char>(cp);
86 }
87 else if (cp <= 0x7FF)
88 {
89 result.resize(2);
90 result[1] = static_cast<char>(0x80 | (0x3f & cp));
91 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
92 }
93 else if (cp <= 0xFFFF)
94 {
95 result.resize(3);
96 result[2] = static_cast<char>(0x80 | (0x3f & cp));
97 result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
98 result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
99 }
100 else if (cp <= 0x10FFFF)
101 {
102 result.resize(4);
103 result[3] = static_cast<char>(0x80 | (0x3f & cp));
104 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
105 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
106 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
107 }
108
109 return result;
110}
111
112
113// Class Reader
114// //////////////////////////////////////////////////////////////////
115
116Reader::Reader()
117 : features_( Features::all() )
118{
119}
120
121
122Reader::Reader( const Features &features )
123 : features_( features )
124{
125}
126
127
128bool
129Reader::parse( const std::string &document,
130 Value &root,
131 bool collectComments )
132{
133 document_ = document;
134 const char *begin = document_.c_str();
135 const char *end = begin + document_.length();
136 return parse( begin, end, root, collectComments );
137}
138
139
140bool
141Reader::parse( std::istream& sin,
142 Value &root,
143 bool collectComments )
144{
145 //std::istream_iterator<char> begin(sin);
146 //std::istream_iterator<char> end;
147 // Those would allow streamed input from a file, if parse() were a
148 // template function.
149
150 // Since std::string is reference-counted, this at least does not
151 // create an extra copy.
152 std::string doc;
153 std::getline(sin, doc, (char)EOF);
154 return parse( doc, root, collectComments );
155}
156
157bool
158Reader::parse( const char *beginDoc, const char *endDoc,
159 Value &root,
160 bool collectComments )
161{
162 if ( !features_.allowComments_ )
163 {
164 collectComments = false;
165 }
166
167 begin_ = beginDoc;
168 end_ = endDoc;
169 collectComments_ = collectComments;
170 current_ = begin_;
171 lastValueEnd_ = 0;
172 lastValue_ = 0;
173 commentsBefore_ = "";
174 errors_.clear();
175 while ( !nodes_.empty() )
176 nodes_.pop();
177 nodes_.push( &root );
178
179 bool successful = readValue();
180 Token token;
181 skipCommentTokens( token );
182 if ( collectComments_ && !commentsBefore_.empty() )
183 root.setComment( commentsBefore_, commentAfter );
184 if ( features_.strictRoot_ )
185 {
186 if ( !root.isArray() && !root.isObject() )
187 {
188 // Set error location to start of doc, ideally should be first token found in doc
189 token.type_ = tokenError;
190 token.start_ = beginDoc;
191 token.end_ = endDoc;
192 addError( "A valid JSON document must be either an array or an object value.",
193 token );
194 return false;
195 }
196 }
197 return successful;
198}
199
200
201bool
202Reader::readValue()
203{
204 Token token;
205 skipCommentTokens( token );
206 bool successful = true;
207
208 if ( collectComments_ && !commentsBefore_.empty() )
209 {
210 currentValue().setComment( commentsBefore_, commentBefore );
211 commentsBefore_ = "";
212 }
213
214
215 switch ( token.type_ )
216 {
217 case tokenObjectBegin:
218 successful = readObject( token );
219 break;
220 case tokenArrayBegin:
221 successful = readArray( token );
222 break;
223 case tokenNumber:
224 successful = decodeNumber( token );
225 break;
226 case tokenString:
227 successful = decodeString( token );
228 break;
229 case tokenTrue:
230 currentValue() = true;
231 break;
232 case tokenFalse:
233 currentValue() = false;
234 break;
235 case tokenNull:
236 currentValue() = Value();
237 break;
238 default:
239 return addError( "Syntax error: value, object or array expected.", token );
240 }
241
242 if ( collectComments_ )
243 {
244 lastValueEnd_ = current_;
245 lastValue_ = ¤tValue();
246 }
247
248 return successful;
249}
250
251
252void
253Reader::skipCommentTokens( Token &token )
254{
255 if ( features_.allowComments_ )
256 {
257 do
258 {
259 readToken( token );
260 }
261 while ( token.type_ == tokenComment );
262 }
263 else
264 {
265 readToken( token );
266 }
267}
268
269
270bool
271Reader::expectToken( TokenType type, Token &token, const char *message )
272{
273 readToken( token );
274 if ( token.type_ != type )
275 return addError( message, token );
276 return true;
277}
278
279
280bool
281Reader::readToken( Token &token )
282{
283 skipSpaces();
284 token.start_ = current_;
285 Char c = getNextChar();
286 bool ok = true;
287 switch ( c )
288 {
289 case '{':
290 token.type_ = tokenObjectBegin;
291 break;
292 case '}':
293 token.type_ = tokenObjectEnd;
294 break;
295 case '[':
296 token.type_ = tokenArrayBegin;
297 break;
298 case ']':
299 token.type_ = tokenArrayEnd;
300 break;
301 case '"':
302 token.type_ = tokenString;
303 ok = readString();
304 break;
305 case '/':
306 token.type_ = tokenComment;
307 ok = readComment();
308 break;
309 case '0':
310 case '1':
311 case '2':
312 case '3':
313 case '4':
314 case '5':
315 case '6':
316 case '7':
317 case '8':
318 case '9':
319 case '-':
320 token.type_ = tokenNumber;
321 readNumber();
322 break;
323 case 't':
324 token.type_ = tokenTrue;
325 ok = match( "rue", 3 );
326 break;
327 case 'f':
328 token.type_ = tokenFalse;
329 ok = match( "alse", 4 );
330 break;
331 case 'n':
332 token.type_ = tokenNull;
333 ok = match( "ull", 3 );
334 break;
335 case ',':
336 token.type_ = tokenArraySeparator;
337 break;
338 case ':':
339 token.type_ = tokenMemberSeparator;
340 break;
341 case 0:
342 token.type_ = tokenEndOfStream;
343 break;
344 default:
345 ok = false;
346 break;
347 }
348 if ( !ok )
349 token.type_ = tokenError;
350 token.end_ = current_;
351 return true;
352}
353
354
355void
356Reader::skipSpaces()
357{
358 while ( current_ != end_ )
359 {
360 Char c = *current_;
361 if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
362 ++current_;
363 else
364 break;
365 }
366}
367
368
369bool
370Reader::match( Location pattern,
371 int patternLength )
372{
373 if ( end_ - current_ < patternLength )
374 return false;
375 int index = patternLength;
376 while ( index-- )
377 if ( current_[index] != pattern[index] )
378 return false;
379 current_ += patternLength;
380 return true;
381}
382
383
384bool
385Reader::readComment()
386{
387 Location commentBegin = current_ - 1;
388 Char c = getNextChar();
389 bool successful = false;
390 if ( c == '*' )
391 successful = readCStyleComment();
392 else if ( c == '/' )
393 successful = readCppStyleComment();
394 if ( !successful )
395 return false;
396
397 if ( collectComments_ )
398 {
399 CommentPlacement placement = commentBefore;
400 if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
401 {
402 if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
403 placement = commentAfterOnSameLine;
404 }
405
406 addComment( commentBegin, current_, placement );
407 }
408 return true;
409}
410
411
412void
413Reader::addComment( Location begin,
414 Location end,
415 CommentPlacement placement )
416{
417 assert( collectComments_ );
418 if ( placement == commentAfterOnSameLine )
419 {
420 assert( lastValue_ != 0 );
421 lastValue_->setComment( std::string( begin, end ), placement );
422 }
423 else
424 {
425 if ( !commentsBefore_.empty() )
426 commentsBefore_ += "\n";
427 commentsBefore_ += std::string( begin, end );
428 }
429}
430
431
432bool
433Reader::readCStyleComment()
434{
435 while ( current_ != end_ )
436 {
437 Char c = getNextChar();
438 if ( c == '*' && *current_ == '/' )
439 break;
440 }
441 return getNextChar() == '/';
442}
443
444
445bool
446Reader::readCppStyleComment()
447{
448 while ( current_ != end_ )
449 {
450 Char c = getNextChar();
451 if ( c == '\r' || c == '\n' )
452 break;
453 }
454 return true;
455}
456
457
458void
459Reader::readNumber()
460{
461 while ( current_ != end_ )
462 {
463 if ( !(*current_ >= '0' && *current_ <= '9') &&
464 !in( *current_, '.', 'e', 'E', '+', '-' ) )
465 break;
466 ++current_;
467 }
468}
469
470bool
471Reader::readString()
472{
473 Char c = 0;
474 while ( current_ != end_ )
475 {
476 c = getNextChar();
477 if ( c == '\\' )
478 getNextChar();
479 else if ( c == '"' )
480 break;
481 }
482 return c == '"';
483}
484
485
486bool
487Reader::readObject( Token &tokenStart )
488{
489 Token tokenName;
490 std::string name;
491 currentValue() = Value( objectValue );
492 while ( readToken( tokenName ) )
493 {
494 bool initialTokenOk = true;
495 while ( tokenName.type_ == tokenComment && initialTokenOk )
496 initialTokenOk = readToken( tokenName );
497 if ( !initialTokenOk )
498 break;
499 if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
500 return true;
501 if ( tokenName.type_ != tokenString )
502 break;
503
504 name = "";
505 if ( !decodeString( tokenName, name ) )
506 return recoverFromError( tokenObjectEnd );
507
508 Token colon;
509 if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
510 {
511 return addErrorAndRecover( "Missing ':' after object member name",
512 colon,
513 tokenObjectEnd );
514 }
515 Value &value = currentValue()[ name ];
516 nodes_.push( &value );
517 bool ok = readValue();
518 nodes_.pop();
519 if ( !ok ) // error already set
520 return recoverFromError( tokenObjectEnd );
521
522 Token comma;
523 if ( !readToken( comma )
524 || ( comma.type_ != tokenObjectEnd &&
525 comma.type_ != tokenArraySeparator &&
526 comma.type_ != tokenComment ) )
527 {
528 return addErrorAndRecover( "Missing ',' or '}' in object declaration",
529 comma,
530 tokenObjectEnd );
531 }
532 bool finalizeTokenOk = true;
533 while ( comma.type_ == tokenComment &&
534 finalizeTokenOk )
535 finalizeTokenOk = readToken( comma );
536 if ( comma.type_ == tokenObjectEnd )
537 return true;
538 }
539 return addErrorAndRecover( "Missing '}' or object member name",
540 tokenName,
541 tokenObjectEnd );
542}
543
544
545bool
546Reader::readArray( Token &tokenStart )
547{
548 currentValue() = Value( arrayValue );
549 skipSpaces();
550 if ( *current_ == ']' ) // empty array
551 {
552 Token endArray;
553 readToken( endArray );
554 return true;
555 }
556 int index = 0;
557 while ( true )
558 {
559 Value &value = currentValue()[ index++ ];
560 nodes_.push( &value );
561 bool ok = readValue();
562 nodes_.pop();
563 if ( !ok ) // error already set
564 return recoverFromError( tokenArrayEnd );
565
566 Token token;
567 // Accept Comment after last item in the array.
568 ok = readToken( token );
569 while ( token.type_ == tokenComment && ok )
570 {
571 ok = readToken( token );
572 }
573 bool badTokenType = ( token.type_ == tokenArraySeparator &&
574 token.type_ == tokenArrayEnd );
575 if ( !ok || badTokenType )
576 {
577 return addErrorAndRecover( "Missing ',' or ']' in array declaration",
578 token,
579 tokenArrayEnd );
580 }
581 if ( token.type_ == tokenArrayEnd )
582 break;
583 }
584 return true;
585}
586
587
588bool
589Reader::decodeNumber( Token &token )
590{
591 bool isDouble = false;
592 for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
593 {
594 isDouble = isDouble
595 || in( *inspect, '.', 'e', 'E', '+' )
596 || ( *inspect == '-' && inspect != token.start_ );
597 }
598 if ( isDouble )
599 return decodeDouble( token );
600 Location current = token.start_;
601 bool isNegative = *current == '-';
602 if ( isNegative )
603 ++current;
604 Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
605 : Value::maxUInt) / 10;
606 Value::UInt value = 0;
607 while ( current < token.end_ )
608 {
609 Char c = *current++;
610 if ( c < '0' || c > '9' )
611 return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
612 if ( value >= threshold )
613 return decodeDouble( token );
614 value = value * 10 + Value::UInt(c - '0');
615 }
616 if ( isNegative )
617 currentValue() = -Value::Int( value );
618 else if ( value <= Value::UInt(Value::maxInt) )
619 currentValue() = Value::Int( value );
620 else
621 currentValue() = value;
622 return true;
623}
624
625
626bool
627Reader::decodeDouble( Token &token )
628{
629 double value = 0;
630 const int bufferSize = 32;
631 int count;
632 int length = int(token.end_ - token.start_);
633 if ( length <= bufferSize )
634 {
635 Char buffer[bufferSize];
636 memcpy( buffer, token.start_, length );
637 buffer[length] = 0;
638 count = sscanf( buffer, "%lf", &value );
639 }
640 else
641 {
642 std::string buffer( token.start_, token.end_ );
643 count = sscanf( buffer.c_str(), "%lf", &value );
644 }
645
646 if ( count != 1 )
647 return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
648 currentValue() = value;
649 return true;
650}
651
652
653bool
654Reader::decodeString( Token &token )
655{
656 std::string decoded;
657 if ( !decodeString( token, decoded ) )
658 return false;
659 currentValue() = decoded;
660 return true;
661}
662
663
664bool
665Reader::decodeString( Token &token, std::string &decoded )
666{
667 decoded.reserve( token.end_ - token.start_ - 2 );
668 Location current = token.start_ + 1; // skip '"'
669 Location end = token.end_ - 1; // do not include '"'
670 while ( current != end )
671 {
672 Char c = *current++;
673 if ( c == '"' )
674 break;
675 else if ( c == '\\' )
676 {
677 if ( current == end )
678 return addError( "Empty escape sequence in string", token, current );
679 Char escape = *current++;
680 switch ( escape )
681 {
682 case '"': decoded += '"'; break;
683 case '/': decoded += '/'; break;
684 case '\\': decoded += '\\'; break;
685 case 'b': decoded += '\b'; break;
686 case 'f': decoded += '\f'; break;
687 case 'n': decoded += '\n'; break;
688 case 'r': decoded += '\r'; break;
689 case 't': decoded += '\t'; break;
690 case 'u':
691 {
692 unsigned int unicode;
693 if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
694 return false;
695 decoded += codePointToUTF8(unicode);
696 }
697 break;
698 default:
699 return addError( "Bad escape sequence in string", token, current );
700 }
701 }
702 else
703 {
704 decoded += c;
705 }
706 }
707 return true;
708}
709
710bool
711Reader::decodeUnicodeCodePoint( Token &token,
712 Location ¤t,
713 Location end,
714 unsigned int &unicode )
715{
716
717 if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
718 return false;
719 if (unicode >= 0xD800 && unicode <= 0xDBFF)
720 {
721 // surrogate pairs
722 if (end - current < 6)
723 return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
724 unsigned int surrogatePair;
725 if (*(current++) == '\\' && *(current++)== 'u')
726 {
727 if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
728 {
729 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
730 }
731 else
732 return false;
733 }
734 else
735 return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
736 }
737 return true;
738}
739
740bool
741Reader::decodeUnicodeEscapeSequence( Token &token,
742 Location ¤t,
743 Location end,
744 unsigned int &unicode )
745{
746 if ( end - current < 4 )
747 return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
748 unicode = 0;
749 for ( int index =0; index < 4; ++index )
750 {
751 Char c = *current++;
752 unicode *= 16;
753 if ( c >= '0' && c <= '9' )
754 unicode += c - '0';
755 else if ( c >= 'a' && c <= 'f' )
756 unicode += c - 'a' + 10;
757 else if ( c >= 'A' && c <= 'F' )
758 unicode += c - 'A' + 10;
759 else
760 return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
761 }
762 return true;
763}
764
765
766bool
767Reader::addError( const std::string &message,
768 Token &token,
769 Location extra )
770{
771 ErrorInfo info;
772 info.token_ = token;
773 info.message_ = message;
774 info.extra_ = extra;
775 errors_.push_back( info );
776 return false;
777}
778
779
780bool
781Reader::recoverFromError( TokenType skipUntilToken )
782{
783 int errorCount = int(errors_.size());
784 Token skip;
785 while ( true )
786 {
787 if ( !readToken(skip) )
788 errors_.resize( errorCount ); // discard errors caused by recovery
789 if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
790 break;
791 }
792 errors_.resize( errorCount );
793 return false;
794}
795
796
797bool
798Reader::addErrorAndRecover( const std::string &message,
799 Token &token,
800 TokenType skipUntilToken )
801{
802 addError( message, token );
803 return recoverFromError( skipUntilToken );
804}
805
806
807Value &
808Reader::currentValue()
809{
810 return *(nodes_.top());
811}
812
813
814Reader::Char
815Reader::getNextChar()
816{
817 if ( current_ == end_ )
818 return 0;
819 return *current_++;
820}
821
822
823void
824Reader::getLocationLineAndColumn( Location location,
825 int &line,
826 int &column ) const
827{
828 Location current = begin_;
829 Location lastLineStart = current;
830 line = 0;
831 while ( current < location && current != end_ )
832 {
833 Char c = *current++;
834 if ( c == '\r' )
835 {
836 if ( *current == '\n' )
837 ++current;
838 lastLineStart = current;
839 ++line;
840 }
841 else if ( c == '\n' )
842 {
843 lastLineStart = current;
844 ++line;
845 }
846 }
847 // column & line start at 1
848 column = int(location - lastLineStart) + 1;
849 ++line;
850}
851
852
853std::string
854Reader::getLocationLineAndColumn( Location location ) const
855{
856 int line, column;
857 getLocationLineAndColumn( location, line, column );
858 char buffer[18+16+16+1];
859 sprintf( buffer, "Line %d, Column %d", line, column );
860 return buffer;
861}
862
863
864std::string
865Reader::getFormatedErrorMessages() const
866{
867 std::string formattedMessage;
868 for ( Errors::const_iterator itError = errors_.begin();
869 itError != errors_.end();
870 ++itError )
871 {
872 const ErrorInfo &error = *itError;
873 formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
874 formattedMessage += " " + error.message_ + "\n";
875 if ( error.extra_ )
876 formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
877 }
878 return formattedMessage;
879}
880
881
882std::istream& operator>>( std::istream &sin, Value &root )
883{
884 Json::Reader reader;
885 bool ok = reader.parse(sin, root, true);
886 //JSON_ASSERT( ok );
887 if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
888 return sin;
889}
890
891
892} // namespace Json