~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/json_server/json/json_writer.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 <plugin/json_server/json/writer.h>
 
39
 
 
40
#include <cassert>
 
41
#include <iomanip>
 
42
#include <iostream>
 
43
#include <sstream>
 
44
#include <stdio.h>
 
45
#include <string.h>
 
46
#include <utility>
 
47
namespace Json {
 
48
 
 
49
static bool isControlCharacter(char ch)
 
50
{
 
51
   return ch > 0 && ch <= 0x1F;
 
52
}
 
53
 
 
54
static bool containsControlCharacter( const char* str )
 
55
{
 
56
   while ( *str ) 
 
57
   {
 
58
      if ( isControlCharacter( *(str++) ) )
 
59
         return true;
 
60
   }
 
61
   return false;
 
62
}
 
63
static void uintToString( unsigned int value, 
 
64
                          char *&current )
 
65
{
 
66
   *--current = 0;
 
67
   do
 
68
   {
 
69
      *--current = (value % 10) + '0';
 
70
      value /= 10;
 
71
   }
 
72
   while ( value != 0 );
 
73
}
 
74
 
 
75
std::string valueToString( Int value )
 
76
{
 
77
   char buffer[32];
 
78
   char *current = buffer + sizeof(buffer);
 
79
   bool isNegative = value < 0;
 
80
   if ( isNegative )
 
81
      value = -value;
 
82
   uintToString( UInt(value), current );
 
83
   if ( isNegative )
 
84
      *--current = '-';
 
85
   assert( current >= buffer );
 
86
   return current;
 
87
}
 
88
 
 
89
 
 
90
std::string valueToString( UInt value )
 
91
{
 
92
   char buffer[32];
 
93
   char *current = buffer + sizeof(buffer);
 
94
   uintToString( value, current );
 
95
   assert( current >= buffer );
 
96
   return current;
 
97
}
 
98
 
 
99
std::string valueToString( double value )
 
100
{
 
101
   char buffer[32];
 
102
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
 
103
   sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
 
104
#else   
 
105
   sprintf(buffer, "%#.16g", value); 
 
106
#endif
 
107
   char* ch = buffer + strlen(buffer) - 1;
 
108
   if (*ch != '0') return buffer; // nothing to truncate, so save time
 
109
   while(ch > buffer && *ch == '0'){
 
110
     --ch;
 
111
   }
 
112
   char* last_nonzero = ch;
 
113
   while(ch >= buffer){
 
114
     switch(*ch){
 
115
     case '0':
 
116
     case '1':
 
117
     case '2':
 
118
     case '3':
 
119
     case '4':
 
120
     case '5':
 
121
     case '6':
 
122
     case '7':
 
123
     case '8':
 
124
     case '9':
 
125
       --ch;
 
126
       continue;
 
127
     case '.':
 
128
       // Truncate zeroes to save bytes in output, but keep one.
 
129
       *(last_nonzero+2) = '\0';
 
130
       return buffer;
 
131
     default:
 
132
       return buffer;
 
133
     }
 
134
   }
 
135
   return buffer;
 
136
}
 
137
 
 
138
 
 
139
std::string valueToString( bool value )
 
140
{
 
141
   return value ? "true" : "false";
 
142
}
 
143
 
 
144
std::string valueToQuotedString( const char *value )
 
145
{
 
146
   // Not sure how to handle unicode...
 
147
   if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
 
148
      return std::string("\"") + value + "\"";
 
149
   // We have to walk value and escape any special characters.
 
150
   // Appending to std::string is not efficient, but this should be rare.
 
151
   // (Note: forward slashes are *not* rare, but I am not escaping them.)
 
152
   unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
 
153
   std::string result;
 
154
   result.reserve(maxsize); // to avoid lots of mallocs
 
155
   result += "\"";
 
156
   for (const char* c=value; *c != 0; ++c)
 
157
   {
 
158
      switch(*c)
 
159
      {
 
160
         case '\"':
 
161
            result += "\\\"";
 
162
            break;
 
163
         case '\\':
 
164
            result += "\\\\";
 
165
            break;
 
166
         case '\b':
 
167
            result += "\\b";
 
168
            break;
 
169
         case '\f':
 
170
            result += "\\f";
 
171
            break;
 
172
         case '\n':
 
173
            result += "\\n";
 
174
            break;
 
175
         case '\r':
 
176
            result += "\\r";
 
177
            break;
 
178
         case '\t':
 
179
            result += "\\t";
 
180
            break;
 
181
         //case '/':
 
182
            // Even though \/ is considered a legal escape in JSON, a bare
 
183
            // slash is also legal, so I see no reason to escape it.
 
184
            // (I hope I am not misunderstanding something.
 
185
            // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
 
186
            // sequence.
 
187
            // Should add a flag to allow this compatibility mode and prevent this 
 
188
            // sequence from occurring.
 
189
         default:
 
190
            if ( isControlCharacter( *c ) )
 
191
            {
 
192
               std::ostringstream oss;
 
193
               oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
 
194
               result += oss.str();
 
195
            }
 
196
            else
 
197
            {
 
198
               result += *c;
 
199
            }
 
200
            break;
 
201
      }
 
202
   }
 
203
   result += "\"";
 
204
   return result;
 
205
}
 
206
 
 
207
// Class Writer
 
208
// //////////////////////////////////////////////////////////////////
 
209
Writer::~Writer()
 
210
{
 
211
}
 
212
 
 
213
 
 
214
// Class FastWriter
 
215
// //////////////////////////////////////////////////////////////////
 
216
 
 
217
FastWriter::FastWriter()
 
218
   : yamlCompatiblityEnabled_( false )
 
219
{
 
220
}
 
221
 
 
222
 
 
223
void 
 
224
FastWriter::enableYAMLCompatibility()
 
225
{
 
226
   yamlCompatiblityEnabled_ = true;
 
227
}
 
228
 
 
229
 
 
230
std::string 
 
231
FastWriter::write( const Value &root )
 
232
{
 
233
   document_ = "";
 
234
   writeValue( root );
 
235
   document_ += "\n";
 
236
   return document_;
 
237
}
 
238
 
 
239
 
 
240
void 
 
241
FastWriter::writeValue( const Value &value )
 
242
{
 
243
   switch ( value.type() )
 
244
   {
 
245
   case nullValue:
 
246
      document_ += "null";
 
247
      break;
 
248
   case intValue:
 
249
      document_ += valueToString( value.asInt() );
 
250
      break;
 
251
   case uintValue:
 
252
      document_ += valueToString( value.asUInt() );
 
253
      break;
 
254
   case realValue:
 
255
      document_ += valueToString( value.asDouble() );
 
256
      break;
 
257
   case stringValue:
 
258
      document_ += valueToQuotedString( value.asCString() );
 
259
      break;
 
260
   case booleanValue:
 
261
      document_ += valueToString( value.asBool() );
 
262
      break;
 
263
   case arrayValue:
 
264
      {
 
265
         document_ += "[";
 
266
         int size = value.size();
 
267
         for ( int index =0; index < size; ++index )
 
268
         {
 
269
            if ( index > 0 )
 
270
               document_ += ",";
 
271
            writeValue( value[index] );
 
272
         }
 
273
         document_ += "]";
 
274
      }
 
275
      break;
 
276
   case objectValue:
 
277
      {
 
278
         Value::Members members( value.getMemberNames() );
 
279
         document_ += "{";
 
280
         for ( Value::Members::iterator it = members.begin(); 
 
281
               it != members.end(); 
 
282
               ++it )
 
283
         {
 
284
            const std::string &name = *it;
 
285
            if ( it != members.begin() )
 
286
               document_ += ",";
 
287
            document_ += valueToQuotedString( name.c_str() );
 
288
            document_ += yamlCompatiblityEnabled_ ? ": " 
 
289
                                                  : ":";
 
290
            writeValue( value[name] );
 
291
         }
 
292
         document_ += "}";
 
293
      }
 
294
      break;
 
295
   }
 
296
}
 
297
 
 
298
 
 
299
// Class StyledWriter
 
300
// //////////////////////////////////////////////////////////////////
 
301
 
 
302
StyledWriter::StyledWriter()
 
303
   : rightMargin_( 74 )
 
304
   , indentSize_( 3 )
 
305
{
 
306
}
 
307
 
 
308
 
 
309
std::string 
 
310
StyledWriter::write( const Value &root )
 
311
{
 
312
   document_ = "";
 
313
   addChildValues_ = false;
 
314
   indentString_ = "";
 
315
   writeCommentBeforeValue( root );
 
316
   writeValue( root );
 
317
   writeCommentAfterValueOnSameLine( root );
 
318
   document_ += "\n";
 
319
   return document_;
 
320
}
 
321
 
 
322
 
 
323
void 
 
324
StyledWriter::writeValue( const Value &value )
 
325
{
 
326
   switch ( value.type() )
 
327
   {
 
328
   case nullValue:
 
329
      pushValue( "null" );
 
330
      break;
 
331
   case intValue:
 
332
      pushValue( valueToString( value.asInt() ) );
 
333
      break;
 
334
   case uintValue:
 
335
      pushValue( valueToString( value.asUInt() ) );
 
336
      break;
 
337
   case realValue:
 
338
      pushValue( valueToString( value.asDouble() ) );
 
339
      break;
 
340
   case stringValue:
 
341
      pushValue( valueToQuotedString( value.asCString() ) );
 
342
      break;
 
343
   case booleanValue:
 
344
      pushValue( valueToString( value.asBool() ) );
 
345
      break;
 
346
   case arrayValue:
 
347
      writeArrayValue( value);
 
348
      break;
 
349
   case objectValue:
 
350
      {
 
351
         Value::Members members( value.getMemberNames() );
 
352
         if ( members.empty() )
 
353
            pushValue( "{}" );
 
354
         else
 
355
         {
 
356
            writeWithIndent( "{" );
 
357
            indent();
 
358
            Value::Members::iterator it = members.begin();
 
359
            while ( true )
 
360
            {
 
361
               const std::string &name = *it;
 
362
               const Value &childValue = value[name];
 
363
               writeCommentBeforeValue( childValue );
 
364
               writeWithIndent( valueToQuotedString( name.c_str() ) );
 
365
               document_ += " : ";
 
366
               writeValue( childValue );
 
367
               if ( ++it == members.end() )
 
368
               {
 
369
                  writeCommentAfterValueOnSameLine( childValue );
 
370
                  break;
 
371
               }
 
372
               document_ += ",";
 
373
               writeCommentAfterValueOnSameLine( childValue );
 
374
            }
 
375
            unindent();
 
376
            writeWithIndent( "}" );
 
377
         }
 
378
      }
 
379
      break;
 
380
   }
 
381
}
 
382
 
 
383
 
 
384
void 
 
385
StyledWriter::writeArrayValue( const Value &value )
 
386
{
 
387
   unsigned size = value.size();
 
388
   if ( size == 0 )
 
389
      pushValue( "[]" );
 
390
   else
 
391
   {
 
392
      bool isArrayMultiLine = isMultineArray( value );
 
393
      if ( isArrayMultiLine )
 
394
      {
 
395
         writeWithIndent( "[" );
 
396
         indent();
 
397
         bool hasChildValue = !childValues_.empty();
 
398
         unsigned index =0;
 
399
         while ( true )
 
400
         {
 
401
            const Value &childValue = value[index];
 
402
            writeCommentBeforeValue( childValue );
 
403
            if ( hasChildValue )
 
404
               writeWithIndent( childValues_[index] );
 
405
            else
 
406
            {
 
407
               writeIndent();
 
408
               writeValue( childValue );
 
409
            }
 
410
            if ( ++index == size )
 
411
            {
 
412
               writeCommentAfterValueOnSameLine( childValue );
 
413
               break;
 
414
            }
 
415
            document_ += ",";
 
416
            writeCommentAfterValueOnSameLine( childValue );
 
417
         }
 
418
         unindent();
 
419
         writeWithIndent( "]" );
 
420
      }
 
421
      else // output on a single line
 
422
      {
 
423
         assert( childValues_.size() == size );
 
424
         document_ += "[ ";
 
425
         for ( unsigned index =0; index < size; ++index )
 
426
         {
 
427
            if ( index > 0 )
 
428
               document_ += ", ";
 
429
            document_ += childValues_[index];
 
430
         }
 
431
         document_ += " ]";
 
432
      }
 
433
   }
 
434
}
 
435
 
 
436
 
 
437
bool 
 
438
StyledWriter::isMultineArray( const Value &value )
 
439
{
 
440
   int size = value.size();
 
441
   bool isMultiLine = size*3 >= rightMargin_ ;
 
442
   childValues_.clear();
 
443
   for ( int index =0; index < size  &&  !isMultiLine; ++index )
 
444
   {
 
445
      const Value &childValue = value[index];
 
446
      isMultiLine = isMultiLine  ||
 
447
                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
 
448
                        childValue.size() > 0 );
 
449
   }
 
450
   if ( !isMultiLine ) // check if line length > max line length
 
451
   {
 
452
      childValues_.reserve( size );
 
453
      addChildValues_ = true;
 
454
      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
 
455
      for ( int index =0; index < size  &&  !isMultiLine; ++index )
 
456
      {
 
457
         writeValue( value[index] );
 
458
         lineLength += int( childValues_[index].length() );
 
459
         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
 
460
      }
 
461
      addChildValues_ = false;
 
462
      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
 
463
   }
 
464
   return isMultiLine;
 
465
}
 
466
 
 
467
 
 
468
void 
 
469
StyledWriter::pushValue( const std::string &value )
 
470
{
 
471
   if ( addChildValues_ )
 
472
      childValues_.push_back( value );
 
473
   else
 
474
      document_ += value;
 
475
}
 
476
 
 
477
 
 
478
void 
 
479
StyledWriter::writeIndent()
 
480
{
 
481
   if ( !document_.empty() )
 
482
   {
 
483
      char last = document_[document_.length()-1];
 
484
      if ( last == ' ' )     // already indented
 
485
         return;
 
486
      if ( last != '\n' )    // Comments may add new-line
 
487
         document_ += '\n';
 
488
   }
 
489
   document_ += indentString_;
 
490
}
 
491
 
 
492
 
 
493
void 
 
494
StyledWriter::writeWithIndent( const std::string &value )
 
495
{
 
496
   writeIndent();
 
497
   document_ += value;
 
498
}
 
499
 
 
500
 
 
501
void 
 
502
StyledWriter::indent()
 
503
{
 
504
   indentString_ += std::string( indentSize_, ' ' );
 
505
}
 
506
 
 
507
 
 
508
void 
 
509
StyledWriter::unindent()
 
510
{
 
511
   assert( int(indentString_.size()) >= indentSize_ );
 
512
   indentString_.resize( indentString_.size() - indentSize_ );
 
513
}
 
514
 
 
515
 
 
516
void 
 
517
StyledWriter::writeCommentBeforeValue( const Value &root )
 
518
{
 
519
   if ( !root.hasComment( commentBefore ) )
 
520
      return;
 
521
   document_ += normalizeEOL( root.getComment( commentBefore ) );
 
522
   document_ += "\n";
 
523
}
 
524
 
 
525
 
 
526
void 
 
527
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
 
528
{
 
529
   if ( root.hasComment( commentAfterOnSameLine ) )
 
530
      document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
 
531
 
 
532
   if ( root.hasComment( commentAfter ) )
 
533
   {
 
534
      document_ += "\n";
 
535
      document_ += normalizeEOL( root.getComment( commentAfter ) );
 
536
      document_ += "\n";
 
537
   }
 
538
}
 
539
 
 
540
 
 
541
bool 
 
542
StyledWriter::hasCommentForValue( const Value &value )
 
543
{
 
544
   return value.hasComment( commentBefore )
 
545
          ||  value.hasComment( commentAfterOnSameLine )
 
546
          ||  value.hasComment( commentAfter );
 
547
}
 
548
 
 
549
 
 
550
std::string 
 
551
StyledWriter::normalizeEOL( const std::string &text )
 
552
{
 
553
   std::string normalized;
 
554
   normalized.reserve( text.length() );
 
555
   const char *begin = text.c_str();
 
556
   const char *end = begin + text.length();
 
557
   const char *current = begin;
 
558
   while ( current != end )
 
559
   {
 
560
      char c = *current++;
 
561
      if ( c == '\r' ) // mac or dos EOL
 
562
      {
 
563
         if ( *current == '\n' ) // convert dos EOL
 
564
            ++current;
 
565
         normalized += '\n';
 
566
      }
 
567
      else // handle unix EOL & other char
 
568
         normalized += c;
 
569
   }
 
570
   return normalized;
 
571
}
 
572
 
 
573
 
 
574
// Class StyledStreamWriter
 
575
// //////////////////////////////////////////////////////////////////
 
576
 
 
577
StyledStreamWriter::StyledStreamWriter( std::string indentation )
 
578
   : document_(NULL)
 
579
   , rightMargin_( 74 )
 
580
   , indentation_( indentation )
 
581
{
 
582
}
 
583
 
 
584
 
 
585
void
 
586
StyledStreamWriter::write( std::ostream &out, const Value &root )
 
587
{
 
588
   document_ = &out;
 
589
   addChildValues_ = false;
 
590
   indentString_ = "";
 
591
   writeCommentBeforeValue( root );
 
592
   writeValue( root );
 
593
   writeCommentAfterValueOnSameLine( root );
 
594
   *document_ << "\n";
 
595
   document_ = NULL; // Forget the stream, for safety.
 
596
}
 
597
 
 
598
 
 
599
void 
 
600
StyledStreamWriter::writeValue( const Value &value )
 
601
{
 
602
   switch ( value.type() )
 
603
   {
 
604
   case nullValue:
 
605
      pushValue( "null" );
 
606
      break;
 
607
   case intValue:
 
608
      pushValue( valueToString( value.asInt() ) );
 
609
      break;
 
610
   case uintValue:
 
611
      pushValue( valueToString( value.asUInt() ) );
 
612
      break;
 
613
   case realValue:
 
614
      pushValue( valueToString( value.asDouble() ) );
 
615
      break;
 
616
   case stringValue:
 
617
      pushValue( valueToQuotedString( value.asCString() ) );
 
618
      break;
 
619
   case booleanValue:
 
620
      pushValue( valueToString( value.asBool() ) );
 
621
      break;
 
622
   case arrayValue:
 
623
      writeArrayValue( value);
 
624
      break;
 
625
   case objectValue:
 
626
      {
 
627
         Value::Members members( value.getMemberNames() );
 
628
         if ( members.empty() )
 
629
            pushValue( "{}" );
 
630
         else
 
631
         {
 
632
            writeWithIndent( "{" );
 
633
            indent();
 
634
            Value::Members::iterator it = members.begin();
 
635
            while ( true )
 
636
            {
 
637
               const std::string &name = *it;
 
638
               const Value &childValue = value[name];
 
639
               writeCommentBeforeValue( childValue );
 
640
               writeWithIndent( valueToQuotedString( name.c_str() ) );
 
641
               *document_ << " : ";
 
642
               writeValue( childValue );
 
643
               if ( ++it == members.end() )
 
644
               {
 
645
                  writeCommentAfterValueOnSameLine( childValue );
 
646
                  break;
 
647
               }
 
648
               *document_ << ",";
 
649
               writeCommentAfterValueOnSameLine( childValue );
 
650
            }
 
651
            unindent();
 
652
            writeWithIndent( "}" );
 
653
         }
 
654
      }
 
655
      break;
 
656
   }
 
657
}
 
658
 
 
659
 
 
660
void 
 
661
StyledStreamWriter::writeArrayValue( const Value &value )
 
662
{
 
663
   unsigned size = value.size();
 
664
   if ( size == 0 )
 
665
      pushValue( "[]" );
 
666
   else
 
667
   {
 
668
      bool isArrayMultiLine = isMultineArray( value );
 
669
      if ( isArrayMultiLine )
 
670
      {
 
671
         writeWithIndent( "[" );
 
672
         indent();
 
673
         bool hasChildValue = !childValues_.empty();
 
674
         unsigned index =0;
 
675
         while ( true )
 
676
         {
 
677
            const Value &childValue = value[index];
 
678
            writeCommentBeforeValue( childValue );
 
679
            if ( hasChildValue )
 
680
               writeWithIndent( childValues_[index] );
 
681
            else
 
682
            {
 
683
               writeIndent();
 
684
               writeValue( childValue );
 
685
            }
 
686
            if ( ++index == size )
 
687
            {
 
688
               writeCommentAfterValueOnSameLine( childValue );
 
689
               break;
 
690
            }
 
691
            *document_ << ",";
 
692
            writeCommentAfterValueOnSameLine( childValue );
 
693
         }
 
694
         unindent();
 
695
         writeWithIndent( "]" );
 
696
      }
 
697
      else // output on a single line
 
698
      {
 
699
         assert( childValues_.size() == size );
 
700
         *document_ << "[ ";
 
701
         for ( unsigned index =0; index < size; ++index )
 
702
         {
 
703
            if ( index > 0 )
 
704
               *document_ << ", ";
 
705
            *document_ << childValues_[index];
 
706
         }
 
707
         *document_ << " ]";
 
708
      }
 
709
   }
 
710
}
 
711
 
 
712
 
 
713
bool 
 
714
StyledStreamWriter::isMultineArray( const Value &value )
 
715
{
 
716
   int size = value.size();
 
717
   bool isMultiLine = size*3 >= rightMargin_ ;
 
718
   childValues_.clear();
 
719
   for ( int index =0; index < size  &&  !isMultiLine; ++index )
 
720
   {
 
721
      const Value &childValue = value[index];
 
722
      isMultiLine = isMultiLine  ||
 
723
                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
 
724
                        childValue.size() > 0 );
 
725
   }
 
726
   if ( !isMultiLine ) // check if line length > max line length
 
727
   {
 
728
      childValues_.reserve( size );
 
729
      addChildValues_ = true;
 
730
      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
 
731
      for ( int index =0; index < size  &&  !isMultiLine; ++index )
 
732
      {
 
733
         writeValue( value[index] );
 
734
         lineLength += int( childValues_[index].length() );
 
735
         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
 
736
      }
 
737
      addChildValues_ = false;
 
738
      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
 
739
   }
 
740
   return isMultiLine;
 
741
}
 
742
 
 
743
 
 
744
void 
 
745
StyledStreamWriter::pushValue( const std::string &value )
 
746
{
 
747
   if ( addChildValues_ )
 
748
      childValues_.push_back( value );
 
749
   else
 
750
      *document_ << value;
 
751
}
 
752
 
 
753
 
 
754
void 
 
755
StyledStreamWriter::writeIndent()
 
756
{
 
757
  /*
 
758
    Some comments in this method would have been nice. ;-)
 
759
 
 
760
   if ( !document_.empty() )
 
761
   {
 
762
      char last = document_[document_.length()-1];
 
763
      if ( last == ' ' )     // already indented
 
764
         return;
 
765
      if ( last != '\n' )    // Comments may add new-line
 
766
         *document_ << '\n';
 
767
   }
 
768
  */
 
769
   *document_ << '\n' << indentString_;
 
770
}
 
771
 
 
772
 
 
773
void 
 
774
StyledStreamWriter::writeWithIndent( const std::string &value )
 
775
{
 
776
   writeIndent();
 
777
   *document_ << value;
 
778
}
 
779
 
 
780
 
 
781
void 
 
782
StyledStreamWriter::indent()
 
783
{
 
784
   indentString_ += indentation_;
 
785
}
 
786
 
 
787
 
 
788
void 
 
789
StyledStreamWriter::unindent()
 
790
{
 
791
   assert( indentString_.size() >= indentation_.size() );
 
792
   indentString_.resize( indentString_.size() - indentation_.size() );
 
793
}
 
794
 
 
795
 
 
796
void 
 
797
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
 
798
{
 
799
   if ( !root.hasComment( commentBefore ) )
 
800
      return;
 
801
   *document_ << normalizeEOL( root.getComment( commentBefore ) );
 
802
   *document_ << "\n";
 
803
}
 
804
 
 
805
 
 
806
void 
 
807
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
 
808
{
 
809
   if ( root.hasComment( commentAfterOnSameLine ) )
 
810
      *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
 
811
 
 
812
   if ( root.hasComment( commentAfter ) )
 
813
   {
 
814
      *document_ << "\n";
 
815
      *document_ << normalizeEOL( root.getComment( commentAfter ) );
 
816
      *document_ << "\n";
 
817
   }
 
818
}
 
819
 
 
820
 
 
821
bool 
 
822
StyledStreamWriter::hasCommentForValue( const Value &value )
 
823
{
 
824
   return value.hasComment( commentBefore )
 
825
          ||  value.hasComment( commentAfterOnSameLine )
 
826
          ||  value.hasComment( commentAfter );
 
827
}
 
828
 
 
829
 
 
830
std::string 
 
831
StyledStreamWriter::normalizeEOL( const std::string &text )
 
832
{
 
833
   std::string normalized;
 
834
   normalized.reserve( text.length() );
 
835
   const char *begin = text.c_str();
 
836
   const char *end = begin + text.length();
 
837
   const char *current = begin;
 
838
   while ( current != end )
 
839
   {
 
840
      char c = *current++;
 
841
      if ( c == '\r' ) // mac or dos EOL
 
842
      {
 
843
         if ( *current == '\n' ) // convert dos EOL
 
844
            ++current;
 
845
         normalized += '\n';
 
846
      }
 
847
      else // handle unix EOL & other char
 
848
         normalized += c;
 
849
   }
 
850
   return normalized;
 
851
}
 
852
 
 
853
 
 
854
std::ostream& operator<<( std::ostream &sout, const Value &root )
 
855
{
 
856
   Json::StyledStreamWriter writer;
 
857
   writer.write(sout, root);
 
858
   return sout;
 
859
}
 
860
 
 
861
 
 
862
} // namespace Json