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