~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/json_server/json/json_reader.cpp

  • Committer: Mark Atwood
  • Date: 2011-05-12 22:20:08 UTC
  • mfrom: (2283.4.17 json-interface)
  • Revision ID: me@mark.atwood.name-20110512222008-7facdn0qu7lsbm0g
mergeĀ lp:~stewart/drizzle/json-interface

Show diffs side-by-side

added added

removed removed

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