arnaucube
arnaucube/commonroutesServerPublic Self-hosted repository
commonroutesServer/www/plugins/ionic-plugin-keyboard/src/blackberry10/native/public/json_reader.cpp
www/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_ = &currentValue();
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 &current, 
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 &current, 
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