Mercurial > hg > soniczoomios
comparison jsoncpp.mm @ 11:58585d6ada62
added another compile flag, changed json to .mm
author | Robert Tubb <rt300@eecs.qmul.ac.uk> |
---|---|
date | Wed, 16 Jan 2013 15:29:16 +0000 |
parents | |
children | 3381c8bf4186 |
comparison
equal
deleted
inserted
replaced
10:a7d6a13287fa | 11:58585d6ada62 |
---|---|
1 /// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). | |
2 /// It is intented to be used with #include <json/json.h> | |
3 | |
4 // ////////////////////////////////////////////////////////////////////// | |
5 // Beginning of content of file: LICENSE | |
6 // ////////////////////////////////////////////////////////////////////// | |
7 | |
8 /* | |
9 The JsonCpp library's source code, including accompanying documentation, | |
10 tests and demonstration applications, are licensed under the following | |
11 conditions... | |
12 | |
13 The author (Baptiste Lepilleur) explicitly disclaims copyright in all | |
14 jurisdictions which recognize such a disclaimer. In such jurisdictions, | |
15 this software is released into the Public Domain. | |
16 | |
17 In jurisdictions which do not recognize Public Domain property (e.g. Germany as of | |
18 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is | |
19 released under the terms of the MIT License (see below). | |
20 | |
21 In jurisdictions which recognize Public Domain property, the user of this | |
22 software may choose to accept it either as 1) Public Domain, 2) under the | |
23 conditions of the MIT License (see below), or 3) under the terms of dual | |
24 Public Domain/MIT License conditions described here, as they choose. | |
25 | |
26 The MIT License is about as close to Public Domain as a license can get, and is | |
27 described in clear, concise terms at: | |
28 | |
29 http://en.wikipedia.org/wiki/MIT_License | |
30 | |
31 The full text of the MIT License follows: | |
32 | |
33 ======================================================================== | |
34 Copyright (c) 2007-2010 Baptiste Lepilleur | |
35 | |
36 Permission is hereby granted, free of charge, to any person | |
37 obtaining a copy of this software and associated documentation | |
38 files (the "Software"), to deal in the Software without | |
39 restriction, including without limitation the rights to use, copy, | |
40 modify, merge, publish, distribute, sublicense, and/or sell copies | |
41 of the Software, and to permit persons to whom the Software is | |
42 furnished to do so, subject to the following conditions: | |
43 | |
44 The above copyright notice and this permission notice shall be | |
45 included in all copies or substantial portions of the Software. | |
46 | |
47 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
48 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
49 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
50 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
51 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
52 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
53 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
54 SOFTWARE. | |
55 ======================================================================== | |
56 (END LICENSE TEXT) | |
57 | |
58 The MIT license is compatible with both the GPL and commercial | |
59 software, affording one all of the rights of Public Domain with the | |
60 minor nuisance of being required to keep the above copyright notice | |
61 and license text in the source code. Note also that by accepting the | |
62 Public Domain "license" you can re-license your copy using whatever | |
63 license you like. | |
64 | |
65 */ | |
66 | |
67 // ////////////////////////////////////////////////////////////////////// | |
68 // End of content of file: LICENSE | |
69 // ////////////////////////////////////////////////////////////////////// | |
70 | |
71 | |
72 | |
73 #define JSON_IS_AMALGAMATION | |
74 | |
75 | |
76 #include <json/json.h> | |
77 | |
78 | |
79 // ////////////////////////////////////////////////////////////////////// | |
80 // Beginning of content of file: src/lib_json/json_tool.h | |
81 // ////////////////////////////////////////////////////////////////////// | |
82 | |
83 // Copyright 2007-2010 Baptiste Lepilleur | |
84 // Distributed under MIT license, or public domain if desired and | |
85 // recognized in your jurisdiction. | |
86 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | |
87 | |
88 #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED | |
89 # define LIB_JSONCPP_JSON_TOOL_H_INCLUDED | |
90 | |
91 /* This header provides common string manipulation support, such as UTF-8, | |
92 * portable conversion from/to string... | |
93 * | |
94 * It is an internal header that must not be exposed. | |
95 */ | |
96 | |
97 namespace Json { | |
98 | |
99 /// Converts a unicode code-point to UTF-8. | |
100 static inline std::string | |
101 codePointToUTF8(unsigned int cp) | |
102 { | |
103 std::string result; | |
104 | |
105 // based on description from http://en.wikipedia.org/wiki/UTF-8 | |
106 | |
107 if (cp <= 0x7f) | |
108 { | |
109 result.resize(1); | |
110 result[0] = static_cast<char>(cp); | |
111 } | |
112 else if (cp <= 0x7FF) | |
113 { | |
114 result.resize(2); | |
115 result[1] = static_cast<char>(0x80 | (0x3f & cp)); | |
116 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); | |
117 } | |
118 else if (cp <= 0xFFFF) | |
119 { | |
120 result.resize(3); | |
121 result[2] = static_cast<char>(0x80 | (0x3f & cp)); | |
122 result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); | |
123 result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); | |
124 } | |
125 else if (cp <= 0x10FFFF) | |
126 { | |
127 result.resize(4); | |
128 result[3] = static_cast<char>(0x80 | (0x3f & cp)); | |
129 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); | |
130 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); | |
131 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); | |
132 } | |
133 | |
134 return result; | |
135 } | |
136 | |
137 | |
138 /// Returns true if ch is a control character (in range [0,32[). | |
139 static inline bool | |
140 isControlCharacter(char ch) | |
141 { | |
142 return ch > 0 && ch <= 0x1F; | |
143 } | |
144 | |
145 | |
146 enum { | |
147 /// Constant that specify the size of the buffer that must be passed to uintToString. | |
148 uintToStringBufferSize = 3*sizeof(LargestUInt)+1 | |
149 }; | |
150 | |
151 // Defines a char buffer for use with uintToString(). | |
152 typedef char UIntToStringBuffer[uintToStringBufferSize]; | |
153 | |
154 | |
155 /** Converts an unsigned integer to string. | |
156 * @param value Unsigned interger to convert to string | |
157 * @param current Input/Output string buffer. | |
158 * Must have at least uintToStringBufferSize chars free. | |
159 */ | |
160 static inline void | |
161 uintToString( LargestUInt value, | |
162 char *¤t ) | |
163 { | |
164 *--current = 0; | |
165 do | |
166 { | |
167 *--current = char(value % 10) + '0'; | |
168 value /= 10; | |
169 } | |
170 while ( value != 0 ); | |
171 } | |
172 | |
173 } // namespace Json { | |
174 | |
175 #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED | |
176 | |
177 // ////////////////////////////////////////////////////////////////////// | |
178 // End of content of file: src/lib_json/json_tool.h | |
179 // ////////////////////////////////////////////////////////////////////// | |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | |
186 // ////////////////////////////////////////////////////////////////////// | |
187 // Beginning of content of file: src/lib_json/json_reader.cpp | |
188 // ////////////////////////////////////////////////////////////////////// | |
189 | |
190 // Copyright 2007-2010 Baptiste Lepilleur | |
191 // Distributed under MIT license, or public domain if desired and | |
192 // recognized in your jurisdiction. | |
193 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | |
194 | |
195 #if !defined(JSON_IS_AMALGAMATION) | |
196 # include <json/reader.h> | |
197 # include <json/value.h> | |
198 # include "json_tool.h" | |
199 #endif // if !defined(JSON_IS_AMALGAMATION) | |
200 #include <utility> | |
201 #include <cstdio> | |
202 #include <cassert> | |
203 #include <cstring> | |
204 #include <iostream> | |
205 #include <stdexcept> | |
206 | |
207 #if _MSC_VER >= 1400 // VC++ 8.0 | |
208 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. | |
209 #endif | |
210 | |
211 namespace Json { | |
212 | |
213 // Implementation of class Features | |
214 // //////////////////////////////// | |
215 | |
216 Features::Features() | |
217 : allowComments_( true ) | |
218 , strictRoot_( false ) | |
219 { | |
220 } | |
221 | |
222 | |
223 Features | |
224 Features::all() | |
225 { | |
226 return Features(); | |
227 } | |
228 | |
229 | |
230 Features | |
231 Features::strictMode() | |
232 { | |
233 Features features; | |
234 features.allowComments_ = false; | |
235 features.strictRoot_ = true; | |
236 return features; | |
237 } | |
238 | |
239 // Implementation of class Reader | |
240 // //////////////////////////////// | |
241 | |
242 | |
243 static inline bool | |
244 in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) | |
245 { | |
246 return c == c1 || c == c2 || c == c3 || c == c4; | |
247 } | |
248 | |
249 static inline bool | |
250 in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) | |
251 { | |
252 return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; | |
253 } | |
254 | |
255 | |
256 static bool | |
257 containsNewLine( Reader::Location begin, | |
258 Reader::Location end ) | |
259 { | |
260 for ( ;begin < end; ++begin ) | |
261 if ( *begin == '\n' || *begin == '\r' ) | |
262 return true; | |
263 return false; | |
264 } | |
265 | |
266 | |
267 // Class Reader | |
268 // ////////////////////////////////////////////////////////////////// | |
269 | |
270 Reader::Reader() | |
271 : features_( Features::all() ) | |
272 { | |
273 } | |
274 | |
275 | |
276 Reader::Reader( const Features &features ) | |
277 : features_( features ) | |
278 { | |
279 } | |
280 | |
281 | |
282 bool | |
283 Reader::parse( const std::string &document, | |
284 Value &root, | |
285 bool collectComments ) | |
286 { | |
287 document_ = document; | |
288 const char *begin = document_.c_str(); | |
289 const char *end = begin + document_.length(); | |
290 return parse( begin, end, root, collectComments ); | |
291 } | |
292 | |
293 | |
294 bool | |
295 Reader::parse( std::istream& sin, | |
296 Value &root, | |
297 bool collectComments ) | |
298 { | |
299 //std::istream_iterator<char> begin(sin); | |
300 //std::istream_iterator<char> end; | |
301 // Those would allow streamed input from a file, if parse() were a | |
302 // template function. | |
303 | |
304 // Since std::string is reference-counted, this at least does not | |
305 // create an extra copy. | |
306 std::string doc; | |
307 std::getline(sin, doc, (char)EOF); | |
308 return parse( doc, root, collectComments ); | |
309 } | |
310 | |
311 bool | |
312 Reader::parse( const char *beginDoc, const char *endDoc, | |
313 Value &root, | |
314 bool collectComments ) | |
315 { | |
316 if ( !features_.allowComments_ ) | |
317 { | |
318 collectComments = false; | |
319 } | |
320 | |
321 begin_ = beginDoc; | |
322 end_ = endDoc; | |
323 collectComments_ = collectComments; | |
324 current_ = begin_; | |
325 lastValueEnd_ = 0; | |
326 lastValue_ = 0; | |
327 commentsBefore_ = ""; | |
328 errors_.clear(); | |
329 while ( !nodes_.empty() ) | |
330 nodes_.pop(); | |
331 nodes_.push( &root ); | |
332 | |
333 bool successful = readValue(); | |
334 Token token; | |
335 skipCommentTokens( token ); | |
336 if ( collectComments_ && !commentsBefore_.empty() ) | |
337 root.setComment( commentsBefore_, commentAfter ); | |
338 if ( features_.strictRoot_ ) | |
339 { | |
340 if ( !root.isArray() && !root.isObject() ) | |
341 { | |
342 // Set error location to start of doc, ideally should be first token found in doc | |
343 token.type_ = tokenError; | |
344 token.start_ = beginDoc; | |
345 token.end_ = endDoc; | |
346 addError( "A valid JSON document must be either an array or an object value.", | |
347 token ); | |
348 return false; | |
349 } | |
350 } | |
351 return successful; | |
352 } | |
353 | |
354 | |
355 bool | |
356 Reader::readValue() | |
357 { | |
358 Token token; | |
359 skipCommentTokens( token ); | |
360 bool successful = true; | |
361 | |
362 if ( collectComments_ && !commentsBefore_.empty() ) | |
363 { | |
364 currentValue().setComment( commentsBefore_, commentBefore ); | |
365 commentsBefore_ = ""; | |
366 } | |
367 | |
368 | |
369 switch ( token.type_ ) | |
370 { | |
371 case tokenObjectBegin: | |
372 successful = readObject( token ); | |
373 break; | |
374 case tokenArrayBegin: | |
375 successful = readArray( token ); | |
376 break; | |
377 case tokenNumber: | |
378 successful = decodeNumber( token ); | |
379 break; | |
380 case tokenString: | |
381 successful = decodeString( token ); | |
382 break; | |
383 case tokenTrue: | |
384 currentValue() = true; | |
385 break; | |
386 case tokenFalse: | |
387 currentValue() = false; | |
388 break; | |
389 case tokenNull: | |
390 currentValue() = Value(); | |
391 break; | |
392 default: | |
393 return addError( "Syntax error: value, object or array expected.", token ); | |
394 } | |
395 | |
396 if ( collectComments_ ) | |
397 { | |
398 lastValueEnd_ = current_; | |
399 lastValue_ = ¤tValue(); | |
400 } | |
401 | |
402 return successful; | |
403 } | |
404 | |
405 | |
406 void | |
407 Reader::skipCommentTokens( Token &token ) | |
408 { | |
409 if ( features_.allowComments_ ) | |
410 { | |
411 do | |
412 { | |
413 readToken( token ); | |
414 } | |
415 while ( token.type_ == tokenComment ); | |
416 } | |
417 else | |
418 { | |
419 readToken( token ); | |
420 } | |
421 } | |
422 | |
423 | |
424 bool | |
425 Reader::expectToken( TokenType type, Token &token, const char *message ) | |
426 { | |
427 readToken( token ); | |
428 if ( token.type_ != type ) | |
429 return addError( message, token ); | |
430 return true; | |
431 } | |
432 | |
433 | |
434 bool | |
435 Reader::readToken( Token &token ) | |
436 { | |
437 skipSpaces(); | |
438 token.start_ = current_; | |
439 Char c = getNextChar(); | |
440 bool ok = true; | |
441 switch ( c ) | |
442 { | |
443 case '{': | |
444 token.type_ = tokenObjectBegin; | |
445 break; | |
446 case '}': | |
447 token.type_ = tokenObjectEnd; | |
448 break; | |
449 case '[': | |
450 token.type_ = tokenArrayBegin; | |
451 break; | |
452 case ']': | |
453 token.type_ = tokenArrayEnd; | |
454 break; | |
455 case '"': | |
456 token.type_ = tokenString; | |
457 ok = readString(); | |
458 break; | |
459 case '/': | |
460 token.type_ = tokenComment; | |
461 ok = readComment(); | |
462 break; | |
463 case '0': | |
464 case '1': | |
465 case '2': | |
466 case '3': | |
467 case '4': | |
468 case '5': | |
469 case '6': | |
470 case '7': | |
471 case '8': | |
472 case '9': | |
473 case '-': | |
474 token.type_ = tokenNumber; | |
475 readNumber(); | |
476 break; | |
477 case 't': | |
478 token.type_ = tokenTrue; | |
479 ok = match( "rue", 3 ); | |
480 break; | |
481 case 'f': | |
482 token.type_ = tokenFalse; | |
483 ok = match( "alse", 4 ); | |
484 break; | |
485 case 'n': | |
486 token.type_ = tokenNull; | |
487 ok = match( "ull", 3 ); | |
488 break; | |
489 case ',': | |
490 token.type_ = tokenArraySeparator; | |
491 break; | |
492 case ':': | |
493 token.type_ = tokenMemberSeparator; | |
494 break; | |
495 case 0: | |
496 token.type_ = tokenEndOfStream; | |
497 break; | |
498 default: | |
499 ok = false; | |
500 break; | |
501 } | |
502 if ( !ok ) | |
503 token.type_ = tokenError; | |
504 token.end_ = current_; | |
505 return true; | |
506 } | |
507 | |
508 | |
509 void | |
510 Reader::skipSpaces() | |
511 { | |
512 while ( current_ != end_ ) | |
513 { | |
514 Char c = *current_; | |
515 if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) | |
516 ++current_; | |
517 else | |
518 break; | |
519 } | |
520 } | |
521 | |
522 | |
523 bool | |
524 Reader::match( Location pattern, | |
525 int patternLength ) | |
526 { | |
527 if ( end_ - current_ < patternLength ) | |
528 return false; | |
529 int index = patternLength; | |
530 while ( index-- ) | |
531 if ( current_[index] != pattern[index] ) | |
532 return false; | |
533 current_ += patternLength; | |
534 return true; | |
535 } | |
536 | |
537 | |
538 bool | |
539 Reader::readComment() | |
540 { | |
541 Location commentBegin = current_ - 1; | |
542 Char c = getNextChar(); | |
543 bool successful = false; | |
544 if ( c == '*' ) | |
545 successful = readCStyleComment(); | |
546 else if ( c == '/' ) | |
547 successful = readCppStyleComment(); | |
548 if ( !successful ) | |
549 return false; | |
550 | |
551 if ( collectComments_ ) | |
552 { | |
553 CommentPlacement placement = commentBefore; | |
554 if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) | |
555 { | |
556 if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) | |
557 placement = commentAfterOnSameLine; | |
558 } | |
559 | |
560 addComment( commentBegin, current_, placement ); | |
561 } | |
562 return true; | |
563 } | |
564 | |
565 | |
566 void | |
567 Reader::addComment( Location begin, | |
568 Location end, | |
569 CommentPlacement placement ) | |
570 { | |
571 assert( collectComments_ ); | |
572 if ( placement == commentAfterOnSameLine ) | |
573 { | |
574 assert( lastValue_ != 0 ); | |
575 lastValue_->setComment( std::string( begin, end ), placement ); | |
576 } | |
577 else | |
578 { | |
579 if ( !commentsBefore_.empty() ) | |
580 commentsBefore_ += "\n"; | |
581 commentsBefore_ += std::string( begin, end ); | |
582 } | |
583 } | |
584 | |
585 | |
586 bool | |
587 Reader::readCStyleComment() | |
588 { | |
589 while ( current_ != end_ ) | |
590 { | |
591 Char c = getNextChar(); | |
592 if ( c == '*' && *current_ == '/' ) | |
593 break; | |
594 } | |
595 return getNextChar() == '/'; | |
596 } | |
597 | |
598 | |
599 bool | |
600 Reader::readCppStyleComment() | |
601 { | |
602 while ( current_ != end_ ) | |
603 { | |
604 Char c = getNextChar(); | |
605 if ( c == '\r' || c == '\n' ) | |
606 break; | |
607 } | |
608 return true; | |
609 } | |
610 | |
611 | |
612 void | |
613 Reader::readNumber() | |
614 { | |
615 while ( current_ != end_ ) | |
616 { | |
617 if ( !(*current_ >= '0' && *current_ <= '9') && | |
618 !in( *current_, '.', 'e', 'E', '+', '-' ) ) | |
619 break; | |
620 ++current_; | |
621 } | |
622 } | |
623 | |
624 bool | |
625 Reader::readString() | |
626 { | |
627 Char c = 0; | |
628 while ( current_ != end_ ) | |
629 { | |
630 c = getNextChar(); | |
631 if ( c == '\\' ) | |
632 getNextChar(); | |
633 else if ( c == '"' ) | |
634 break; | |
635 } | |
636 return c == '"'; | |
637 } | |
638 | |
639 | |
640 bool | |
641 Reader::readObject( Token &/*tokenStart*/ ) | |
642 { | |
643 Token tokenName; | |
644 std::string name; | |
645 currentValue() = Value( objectValue ); | |
646 while ( readToken( tokenName ) ) | |
647 { | |
648 bool initialTokenOk = true; | |
649 while ( tokenName.type_ == tokenComment && initialTokenOk ) | |
650 initialTokenOk = readToken( tokenName ); | |
651 if ( !initialTokenOk ) | |
652 break; | |
653 if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object | |
654 return true; | |
655 if ( tokenName.type_ != tokenString ) | |
656 break; | |
657 | |
658 name = ""; | |
659 if ( !decodeString( tokenName, name ) ) | |
660 return recoverFromError( tokenObjectEnd ); | |
661 | |
662 Token colon; | |
663 if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) | |
664 { | |
665 return addErrorAndRecover( "Missing ':' after object member name", | |
666 colon, | |
667 tokenObjectEnd ); | |
668 } | |
669 Value &value = currentValue()[ name ]; | |
670 nodes_.push( &value ); | |
671 bool ok = readValue(); | |
672 nodes_.pop(); | |
673 if ( !ok ) // error already set | |
674 return recoverFromError( tokenObjectEnd ); | |
675 | |
676 Token comma; | |
677 if ( !readToken( comma ) | |
678 || ( comma.type_ != tokenObjectEnd && | |
679 comma.type_ != tokenArraySeparator && | |
680 comma.type_ != tokenComment ) ) | |
681 { | |
682 return addErrorAndRecover( "Missing ',' or '}' in object declaration", | |
683 comma, | |
684 tokenObjectEnd ); | |
685 } | |
686 bool finalizeTokenOk = true; | |
687 while ( comma.type_ == tokenComment && | |
688 finalizeTokenOk ) | |
689 finalizeTokenOk = readToken( comma ); | |
690 if ( comma.type_ == tokenObjectEnd ) | |
691 return true; | |
692 } | |
693 return addErrorAndRecover( "Missing '}' or object member name", | |
694 tokenName, | |
695 tokenObjectEnd ); | |
696 } | |
697 | |
698 | |
699 bool | |
700 Reader::readArray( Token &/*tokenStart*/ ) | |
701 { | |
702 currentValue() = Value( arrayValue ); | |
703 skipSpaces(); | |
704 if ( *current_ == ']' ) // empty array | |
705 { | |
706 Token endArray; | |
707 readToken( endArray ); | |
708 return true; | |
709 } | |
710 int index = 0; | |
711 for (;;) | |
712 { | |
713 Value &value = currentValue()[ index++ ]; | |
714 nodes_.push( &value ); | |
715 bool ok = readValue(); | |
716 nodes_.pop(); | |
717 if ( !ok ) // error already set | |
718 return recoverFromError( tokenArrayEnd ); | |
719 | |
720 Token token; | |
721 // Accept Comment after last item in the array. | |
722 ok = readToken( token ); | |
723 while ( token.type_ == tokenComment && ok ) | |
724 { | |
725 ok = readToken( token ); | |
726 } | |
727 bool badTokenType = ( token.type_ != tokenArraySeparator && | |
728 token.type_ != tokenArrayEnd ); | |
729 if ( !ok || badTokenType ) | |
730 { | |
731 return addErrorAndRecover( "Missing ',' or ']' in array declaration", | |
732 token, | |
733 tokenArrayEnd ); | |
734 } | |
735 if ( token.type_ == tokenArrayEnd ) | |
736 break; | |
737 } | |
738 return true; | |
739 } | |
740 | |
741 | |
742 bool | |
743 Reader::decodeNumber( Token &token ) | |
744 { | |
745 bool isDouble = false; | |
746 for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) | |
747 { | |
748 isDouble = isDouble | |
749 || in( *inspect, '.', 'e', 'E', '+' ) | |
750 || ( *inspect == '-' && inspect != token.start_ ); | |
751 } | |
752 if ( isDouble ) | |
753 return decodeDouble( token ); | |
754 // Attempts to parse the number as an integer. If the number is | |
755 // larger than the maximum supported value of an integer then | |
756 // we decode the number as a double. | |
757 Location current = token.start_; | |
758 bool isNegative = *current == '-'; | |
759 if ( isNegative ) | |
760 ++current; | |
761 Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) | |
762 : Value::maxLargestUInt; | |
763 Value::LargestUInt threshold = maxIntegerValue / 10; | |
764 Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 ); | |
765 assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 ); | |
766 Value::LargestUInt value = 0; | |
767 while ( current < token.end_ ) | |
768 { | |
769 Char c = *current++; | |
770 if ( c < '0' || c > '9' ) | |
771 return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); | |
772 Value::UInt digit(c - '0'); | |
773 if ( value >= threshold ) | |
774 { | |
775 // If the current digit is not the last one, or if it is | |
776 // greater than the last digit of the maximum integer value, | |
777 // the parse the number as a double. | |
778 if ( current != token.end_ || digit > lastDigitThreshold ) | |
779 { | |
780 return decodeDouble( token ); | |
781 } | |
782 } | |
783 value = value * 10 + digit; | |
784 } | |
785 if ( isNegative ) | |
786 currentValue() = -Value::LargestInt( value ); | |
787 else if ( value <= Value::LargestUInt(Value::maxInt) ) | |
788 currentValue() = Value::LargestInt( value ); | |
789 else | |
790 currentValue() = value; | |
791 return true; | |
792 } | |
793 | |
794 | |
795 bool | |
796 Reader::decodeDouble( Token &token ) | |
797 { | |
798 double value = 0; | |
799 const int bufferSize = 32; | |
800 int count; | |
801 int length = int(token.end_ - token.start_); | |
802 if ( length <= bufferSize ) | |
803 { | |
804 Char buffer[bufferSize+1]; | |
805 memcpy( buffer, token.start_, length ); | |
806 buffer[length] = 0; | |
807 count = sscanf( buffer, "%lf", &value ); | |
808 } | |
809 else | |
810 { | |
811 std::string buffer( token.start_, token.end_ ); | |
812 count = sscanf( buffer.c_str(), "%lf", &value ); | |
813 } | |
814 | |
815 if ( count != 1 ) | |
816 return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); | |
817 currentValue() = value; | |
818 return true; | |
819 } | |
820 | |
821 | |
822 bool | |
823 Reader::decodeString( Token &token ) | |
824 { | |
825 std::string decoded; | |
826 if ( !decodeString( token, decoded ) ) | |
827 return false; | |
828 currentValue() = decoded; | |
829 return true; | |
830 } | |
831 | |
832 | |
833 bool | |
834 Reader::decodeString( Token &token, std::string &decoded ) | |
835 { | |
836 decoded.reserve( token.end_ - token.start_ - 2 ); | |
837 Location current = token.start_ + 1; // skip '"' | |
838 Location end = token.end_ - 1; // do not include '"' | |
839 while ( current != end ) | |
840 { | |
841 Char c = *current++; | |
842 if ( c == '"' ) | |
843 break; | |
844 else if ( c == '\\' ) | |
845 { | |
846 if ( current == end ) | |
847 return addError( "Empty escape sequence in string", token, current ); | |
848 Char escape = *current++; | |
849 switch ( escape ) | |
850 { | |
851 case '"': decoded += '"'; break; | |
852 case '/': decoded += '/'; break; | |
853 case '\\': decoded += '\\'; break; | |
854 case 'b': decoded += '\b'; break; | |
855 case 'f': decoded += '\f'; break; | |
856 case 'n': decoded += '\n'; break; | |
857 case 'r': decoded += '\r'; break; | |
858 case 't': decoded += '\t'; break; | |
859 case 'u': | |
860 { | |
861 unsigned int unicode; | |
862 if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) | |
863 return false; | |
864 decoded += codePointToUTF8(unicode); | |
865 } | |
866 break; | |
867 default: | |
868 return addError( "Bad escape sequence in string", token, current ); | |
869 } | |
870 } | |
871 else | |
872 { | |
873 decoded += c; | |
874 } | |
875 } | |
876 return true; | |
877 } | |
878 | |
879 bool | |
880 Reader::decodeUnicodeCodePoint( Token &token, | |
881 Location ¤t, | |
882 Location end, | |
883 unsigned int &unicode ) | |
884 { | |
885 | |
886 if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) | |
887 return false; | |
888 if (unicode >= 0xD800 && unicode <= 0xDBFF) | |
889 { | |
890 // surrogate pairs | |
891 if (end - current < 6) | |
892 return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); | |
893 unsigned int surrogatePair; | |
894 if (*(current++) == '\\' && *(current++)== 'u') | |
895 { | |
896 if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) | |
897 { | |
898 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); | |
899 } | |
900 else | |
901 return false; | |
902 } | |
903 else | |
904 return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); | |
905 } | |
906 return true; | |
907 } | |
908 | |
909 bool | |
910 Reader::decodeUnicodeEscapeSequence( Token &token, | |
911 Location ¤t, | |
912 Location end, | |
913 unsigned int &unicode ) | |
914 { | |
915 if ( end - current < 4 ) | |
916 return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); | |
917 unicode = 0; | |
918 for ( int index =0; index < 4; ++index ) | |
919 { | |
920 Char c = *current++; | |
921 unicode *= 16; | |
922 if ( c >= '0' && c <= '9' ) | |
923 unicode += c - '0'; | |
924 else if ( c >= 'a' && c <= 'f' ) | |
925 unicode += c - 'a' + 10; | |
926 else if ( c >= 'A' && c <= 'F' ) | |
927 unicode += c - 'A' + 10; | |
928 else | |
929 return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); | |
930 } | |
931 return true; | |
932 } | |
933 | |
934 | |
935 bool | |
936 Reader::addError( const std::string &message, | |
937 Token &token, | |
938 Location extra ) | |
939 { | |
940 ErrorInfo info; | |
941 info.token_ = token; | |
942 info.message_ = message; | |
943 info.extra_ = extra; | |
944 errors_.push_back( info ); | |
945 return false; | |
946 } | |
947 | |
948 | |
949 bool | |
950 Reader::recoverFromError( TokenType skipUntilToken ) | |
951 { | |
952 int errorCount = int(errors_.size()); | |
953 Token skip; | |
954 for (;;) | |
955 { | |
956 if ( !readToken(skip) ) | |
957 errors_.resize( errorCount ); // discard errors caused by recovery | |
958 if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) | |
959 break; | |
960 } | |
961 errors_.resize( errorCount ); | |
962 return false; | |
963 } | |
964 | |
965 | |
966 bool | |
967 Reader::addErrorAndRecover( const std::string &message, | |
968 Token &token, | |
969 TokenType skipUntilToken ) | |
970 { | |
971 addError( message, token ); | |
972 return recoverFromError( skipUntilToken ); | |
973 } | |
974 | |
975 | |
976 Value & | |
977 Reader::currentValue() | |
978 { | |
979 return *(nodes_.top()); | |
980 } | |
981 | |
982 | |
983 Reader::Char | |
984 Reader::getNextChar() | |
985 { | |
986 if ( current_ == end_ ) | |
987 return 0; | |
988 return *current_++; | |
989 } | |
990 | |
991 | |
992 void | |
993 Reader::getLocationLineAndColumn( Location location, | |
994 int &line, | |
995 int &column ) const | |
996 { | |
997 Location current = begin_; | |
998 Location lastLineStart = current; | |
999 line = 0; | |
1000 while ( current < location && current != end_ ) | |
1001 { | |
1002 Char c = *current++; | |
1003 if ( c == '\r' ) | |
1004 { | |
1005 if ( *current == '\n' ) | |
1006 ++current; | |
1007 lastLineStart = current; | |
1008 ++line; | |
1009 } | |
1010 else if ( c == '\n' ) | |
1011 { | |
1012 lastLineStart = current; | |
1013 ++line; | |
1014 } | |
1015 } | |
1016 // column & line start at 1 | |
1017 column = int(location - lastLineStart) + 1; | |
1018 ++line; | |
1019 } | |
1020 | |
1021 | |
1022 std::string | |
1023 Reader::getLocationLineAndColumn( Location location ) const | |
1024 { | |
1025 int line, column; | |
1026 getLocationLineAndColumn( location, line, column ); | |
1027 char buffer[18+16+16+1]; | |
1028 sprintf( buffer, "Line %d, Column %d", line, column ); | |
1029 return buffer; | |
1030 } | |
1031 | |
1032 | |
1033 // Deprecated. Preserved for backward compatibility | |
1034 std::string | |
1035 Reader::getFormatedErrorMessages() const | |
1036 { | |
1037 return getFormattedErrorMessages(); | |
1038 } | |
1039 | |
1040 | |
1041 std::string | |
1042 Reader::getFormattedErrorMessages() const | |
1043 { | |
1044 std::string formattedMessage; | |
1045 for ( Errors::const_iterator itError = errors_.begin(); | |
1046 itError != errors_.end(); | |
1047 ++itError ) | |
1048 { | |
1049 const ErrorInfo &error = *itError; | |
1050 formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; | |
1051 formattedMessage += " " + error.message_ + "\n"; | |
1052 if ( error.extra_ ) | |
1053 formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; | |
1054 } | |
1055 return formattedMessage; | |
1056 } | |
1057 | |
1058 | |
1059 std::istream& operator>>( std::istream &sin, Value &root ) | |
1060 { | |
1061 Json::Reader reader; | |
1062 bool ok = reader.parse(sin, root, true); | |
1063 //JSON_ASSERT( ok ); | |
1064 if (!ok) throw std::runtime_error(reader.getFormattedErrorMessages()); | |
1065 return sin; | |
1066 } | |
1067 | |
1068 | |
1069 } // namespace Json | |
1070 | |
1071 // ////////////////////////////////////////////////////////////////////// | |
1072 // End of content of file: src/lib_json/json_reader.cpp | |
1073 // ////////////////////////////////////////////////////////////////////// | |
1074 | |
1075 | |
1076 | |
1077 | |
1078 | |
1079 | |
1080 // ////////////////////////////////////////////////////////////////////// | |
1081 // Beginning of content of file: src/lib_json/json_batchallocator.h | |
1082 // ////////////////////////////////////////////////////////////////////// | |
1083 | |
1084 // Copyright 2007-2010 Baptiste Lepilleur | |
1085 // Distributed under MIT license, or public domain if desired and | |
1086 // recognized in your jurisdiction. | |
1087 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | |
1088 | |
1089 #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED | |
1090 # define JSONCPP_BATCHALLOCATOR_H_INCLUDED | |
1091 | |
1092 # include <stdlib.h> | |
1093 # include <assert.h> | |
1094 | |
1095 # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION | |
1096 | |
1097 namespace Json { | |
1098 | |
1099 /* Fast memory allocator. | |
1100 * | |
1101 * This memory allocator allocates memory for a batch of object (specified by | |
1102 * the page size, the number of object in each page). | |
1103 * | |
1104 * It does not allow the destruction of a single object. All the allocated objects | |
1105 * can be destroyed at once. The memory can be either released or reused for future | |
1106 * allocation. | |
1107 * | |
1108 * The in-place new operator must be used to construct the object using the pointer | |
1109 * returned by allocate. | |
1110 */ | |
1111 template<typename AllocatedType | |
1112 ,const unsigned int objectPerAllocation> | |
1113 class BatchAllocator | |
1114 { | |
1115 public: | |
1116 typedef AllocatedType Type; | |
1117 | |
1118 BatchAllocator( unsigned int objectsPerPage = 255 ) | |
1119 : freeHead_( 0 ) | |
1120 , objectsPerPage_( objectsPerPage ) | |
1121 { | |
1122 // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); | |
1123 assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. | |
1124 assert( objectsPerPage >= 16 ); | |
1125 batches_ = allocateBatch( 0 ); // allocated a dummy page | |
1126 currentBatch_ = batches_; | |
1127 } | |
1128 | |
1129 ~BatchAllocator() | |
1130 { | |
1131 for ( BatchInfo *batch = batches_; batch; ) | |
1132 { | |
1133 BatchInfo *nextBatch = batch->next_; | |
1134 free( batch ); | |
1135 batch = nextBatch; | |
1136 } | |
1137 } | |
1138 | |
1139 /// allocate space for an array of objectPerAllocation object. | |
1140 /// @warning it is the responsability of the caller to call objects constructors. | |
1141 AllocatedType *allocate() | |
1142 { | |
1143 if ( freeHead_ ) // returns node from free list. | |
1144 { | |
1145 AllocatedType *object = freeHead_; | |
1146 freeHead_ = *(AllocatedType **)object; | |
1147 return object; | |
1148 } | |
1149 if ( currentBatch_->used_ == currentBatch_->end_ ) | |
1150 { | |
1151 currentBatch_ = currentBatch_->next_; | |
1152 while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) | |
1153 currentBatch_ = currentBatch_->next_; | |
1154 | |
1155 if ( !currentBatch_ ) // no free batch found, allocate a new one | |
1156 { | |
1157 currentBatch_ = allocateBatch( objectsPerPage_ ); | |
1158 currentBatch_->next_ = batches_; // insert at the head of the list | |
1159 batches_ = currentBatch_; | |
1160 } | |
1161 } | |
1162 AllocatedType *allocated = currentBatch_->used_; | |
1163 currentBatch_->used_ += objectPerAllocation; | |
1164 return allocated; | |
1165 } | |
1166 | |
1167 /// Release the object. | |
1168 /// @warning it is the responsability of the caller to actually destruct the object. | |
1169 void release( AllocatedType *object ) | |
1170 { | |
1171 assert( object != 0 ); | |
1172 *(AllocatedType **)object = freeHead_; | |
1173 freeHead_ = object; | |
1174 } | |
1175 | |
1176 private: | |
1177 struct BatchInfo | |
1178 { | |
1179 BatchInfo *next_; | |
1180 AllocatedType *used_; | |
1181 AllocatedType *end_; | |
1182 AllocatedType buffer_[objectPerAllocation]; | |
1183 }; | |
1184 | |
1185 // disabled copy constructor and assignement operator. | |
1186 BatchAllocator( const BatchAllocator & ); | |
1187 void operator =( const BatchAllocator &); | |
1188 | |
1189 static BatchInfo *allocateBatch( unsigned int objectsPerPage ) | |
1190 { | |
1191 const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation | |
1192 + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; | |
1193 BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); | |
1194 batch->next_ = 0; | |
1195 batch->used_ = batch->buffer_; | |
1196 batch->end_ = batch->buffer_ + objectsPerPage; | |
1197 return batch; | |
1198 } | |
1199 | |
1200 BatchInfo *batches_; | |
1201 BatchInfo *currentBatch_; | |
1202 /// Head of a single linked list within the allocated space of freeed object | |
1203 AllocatedType *freeHead_; | |
1204 unsigned int objectsPerPage_; | |
1205 }; | |
1206 | |
1207 | |
1208 } // namespace Json | |
1209 | |
1210 # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION | |
1211 | |
1212 #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED | |
1213 | |
1214 | |
1215 // ////////////////////////////////////////////////////////////////////// | |
1216 // End of content of file: src/lib_json/json_batchallocator.h | |
1217 // ////////////////////////////////////////////////////////////////////// | |
1218 | |
1219 | |
1220 | |
1221 | |
1222 | |
1223 | |
1224 // ////////////////////////////////////////////////////////////////////// | |
1225 // Beginning of content of file: src/lib_json/json_valueiterator.inl | |
1226 // ////////////////////////////////////////////////////////////////////// | |
1227 | |
1228 // Copyright 2007-2010 Baptiste Lepilleur | |
1229 // Distributed under MIT license, or public domain if desired and | |
1230 // recognized in your jurisdiction. | |
1231 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | |
1232 | |
1233 // included by json_value.cpp | |
1234 | |
1235 namespace Json { | |
1236 | |
1237 // ////////////////////////////////////////////////////////////////// | |
1238 // ////////////////////////////////////////////////////////////////// | |
1239 // ////////////////////////////////////////////////////////////////// | |
1240 // class ValueIteratorBase | |
1241 // ////////////////////////////////////////////////////////////////// | |
1242 // ////////////////////////////////////////////////////////////////// | |
1243 // ////////////////////////////////////////////////////////////////// | |
1244 | |
1245 ValueIteratorBase::ValueIteratorBase() | |
1246 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1247 : current_() | |
1248 , isNull_( true ) | |
1249 { | |
1250 } | |
1251 #else | |
1252 : isArray_( true ) | |
1253 , isNull_( true ) | |
1254 { | |
1255 iterator_.array_ = ValueInternalArray::IteratorState(); | |
1256 } | |
1257 #endif | |
1258 | |
1259 | |
1260 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1261 ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) | |
1262 : current_( current ) | |
1263 , isNull_( false ) | |
1264 { | |
1265 } | |
1266 #else | |
1267 ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) | |
1268 : isArray_( true ) | |
1269 { | |
1270 iterator_.array_ = state; | |
1271 } | |
1272 | |
1273 | |
1274 ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) | |
1275 : isArray_( false ) | |
1276 { | |
1277 iterator_.map_ = state; | |
1278 } | |
1279 #endif | |
1280 | |
1281 Value & | |
1282 ValueIteratorBase::deref() const | |
1283 { | |
1284 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1285 return current_->second; | |
1286 #else | |
1287 if ( isArray_ ) | |
1288 return ValueInternalArray::dereference( iterator_.array_ ); | |
1289 return ValueInternalMap::value( iterator_.map_ ); | |
1290 #endif | |
1291 } | |
1292 | |
1293 | |
1294 void | |
1295 ValueIteratorBase::increment() | |
1296 { | |
1297 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1298 ++current_; | |
1299 #else | |
1300 if ( isArray_ ) | |
1301 ValueInternalArray::increment( iterator_.array_ ); | |
1302 ValueInternalMap::increment( iterator_.map_ ); | |
1303 #endif | |
1304 } | |
1305 | |
1306 | |
1307 void | |
1308 ValueIteratorBase::decrement() | |
1309 { | |
1310 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1311 --current_; | |
1312 #else | |
1313 if ( isArray_ ) | |
1314 ValueInternalArray::decrement( iterator_.array_ ); | |
1315 ValueInternalMap::decrement( iterator_.map_ ); | |
1316 #endif | |
1317 } | |
1318 | |
1319 | |
1320 ValueIteratorBase::difference_type | |
1321 ValueIteratorBase::computeDistance( const SelfType &other ) const | |
1322 { | |
1323 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1324 # ifdef JSON_USE_CPPTL_SMALLMAP | |
1325 return current_ - other.current_; | |
1326 # else | |
1327 // Iterator for null value are initialized using the default | |
1328 // constructor, which initialize current_ to the default | |
1329 // std::map::iterator. As begin() and end() are two instance | |
1330 // of the default std::map::iterator, they can not be compared. | |
1331 // To allow this, we handle this comparison specifically. | |
1332 if ( isNull_ && other.isNull_ ) | |
1333 { | |
1334 return 0; | |
1335 } | |
1336 | |
1337 | |
1338 // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, | |
1339 // which is the one used by default). | |
1340 // Using a portable hand-made version for non random iterator instead: | |
1341 // return difference_type( std::distance( current_, other.current_ ) ); | |
1342 difference_type myDistance = 0; | |
1343 for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) | |
1344 { | |
1345 ++myDistance; | |
1346 } | |
1347 return myDistance; | |
1348 # endif | |
1349 #else | |
1350 if ( isArray_ ) | |
1351 return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); | |
1352 return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); | |
1353 #endif | |
1354 } | |
1355 | |
1356 | |
1357 bool | |
1358 ValueIteratorBase::isEqual( const SelfType &other ) const | |
1359 { | |
1360 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1361 if ( isNull_ ) | |
1362 { | |
1363 return other.isNull_; | |
1364 } | |
1365 return current_ == other.current_; | |
1366 #else | |
1367 if ( isArray_ ) | |
1368 return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); | |
1369 return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); | |
1370 #endif | |
1371 } | |
1372 | |
1373 | |
1374 void | |
1375 ValueIteratorBase::copy( const SelfType &other ) | |
1376 { | |
1377 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1378 current_ = other.current_; | |
1379 #else | |
1380 if ( isArray_ ) | |
1381 iterator_.array_ = other.iterator_.array_; | |
1382 iterator_.map_ = other.iterator_.map_; | |
1383 #endif | |
1384 } | |
1385 | |
1386 | |
1387 Value | |
1388 ValueIteratorBase::key() const | |
1389 { | |
1390 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1391 const Value::CZString czstring = (*current_).first; | |
1392 if ( czstring.c_str() ) | |
1393 { | |
1394 if ( czstring.isStaticString() ) | |
1395 return Value( StaticString( czstring.c_str() ) ); | |
1396 return Value( czstring.c_str() ); | |
1397 } | |
1398 return Value( czstring.index() ); | |
1399 #else | |
1400 if ( isArray_ ) | |
1401 return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); | |
1402 bool isStatic; | |
1403 const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); | |
1404 if ( isStatic ) | |
1405 return Value( StaticString( memberName ) ); | |
1406 return Value( memberName ); | |
1407 #endif | |
1408 } | |
1409 | |
1410 | |
1411 UInt | |
1412 ValueIteratorBase::index() const | |
1413 { | |
1414 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1415 const Value::CZString czstring = (*current_).first; | |
1416 if ( !czstring.c_str() ) | |
1417 return czstring.index(); | |
1418 return Value::UInt( -1 ); | |
1419 #else | |
1420 if ( isArray_ ) | |
1421 return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); | |
1422 return Value::UInt( -1 ); | |
1423 #endif | |
1424 } | |
1425 | |
1426 | |
1427 const char * | |
1428 ValueIteratorBase::memberName() const | |
1429 { | |
1430 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1431 const char *name = (*current_).first.c_str(); | |
1432 return name ? name : ""; | |
1433 #else | |
1434 if ( !isArray_ ) | |
1435 return ValueInternalMap::key( iterator_.map_ ); | |
1436 return ""; | |
1437 #endif | |
1438 } | |
1439 | |
1440 | |
1441 // ////////////////////////////////////////////////////////////////// | |
1442 // ////////////////////////////////////////////////////////////////// | |
1443 // ////////////////////////////////////////////////////////////////// | |
1444 // class ValueConstIterator | |
1445 // ////////////////////////////////////////////////////////////////// | |
1446 // ////////////////////////////////////////////////////////////////// | |
1447 // ////////////////////////////////////////////////////////////////// | |
1448 | |
1449 ValueConstIterator::ValueConstIterator() | |
1450 { | |
1451 } | |
1452 | |
1453 | |
1454 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1455 ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) | |
1456 : ValueIteratorBase( current ) | |
1457 { | |
1458 } | |
1459 #else | |
1460 ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) | |
1461 : ValueIteratorBase( state ) | |
1462 { | |
1463 } | |
1464 | |
1465 ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) | |
1466 : ValueIteratorBase( state ) | |
1467 { | |
1468 } | |
1469 #endif | |
1470 | |
1471 ValueConstIterator & | |
1472 ValueConstIterator::operator =( const ValueIteratorBase &other ) | |
1473 { | |
1474 copy( other ); | |
1475 return *this; | |
1476 } | |
1477 | |
1478 | |
1479 // ////////////////////////////////////////////////////////////////// | |
1480 // ////////////////////////////////////////////////////////////////// | |
1481 // ////////////////////////////////////////////////////////////////// | |
1482 // class ValueIterator | |
1483 // ////////////////////////////////////////////////////////////////// | |
1484 // ////////////////////////////////////////////////////////////////// | |
1485 // ////////////////////////////////////////////////////////////////// | |
1486 | |
1487 ValueIterator::ValueIterator() | |
1488 { | |
1489 } | |
1490 | |
1491 | |
1492 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1493 ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) | |
1494 : ValueIteratorBase( current ) | |
1495 { | |
1496 } | |
1497 #else | |
1498 ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) | |
1499 : ValueIteratorBase( state ) | |
1500 { | |
1501 } | |
1502 | |
1503 ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) | |
1504 : ValueIteratorBase( state ) | |
1505 { | |
1506 } | |
1507 #endif | |
1508 | |
1509 ValueIterator::ValueIterator( const ValueConstIterator &other ) | |
1510 : ValueIteratorBase( other ) | |
1511 { | |
1512 } | |
1513 | |
1514 ValueIterator::ValueIterator( const ValueIterator &other ) | |
1515 : ValueIteratorBase( other ) | |
1516 { | |
1517 } | |
1518 | |
1519 ValueIterator & | |
1520 ValueIterator::operator =( const SelfType &other ) | |
1521 { | |
1522 copy( other ); | |
1523 return *this; | |
1524 } | |
1525 | |
1526 } // namespace Json | |
1527 | |
1528 // ////////////////////////////////////////////////////////////////////// | |
1529 // End of content of file: src/lib_json/json_valueiterator.inl | |
1530 // ////////////////////////////////////////////////////////////////////// | |
1531 | |
1532 | |
1533 | |
1534 | |
1535 | |
1536 | |
1537 // ////////////////////////////////////////////////////////////////////// | |
1538 // Beginning of content of file: src/lib_json/json_value.cpp | |
1539 // ////////////////////////////////////////////////////////////////////// | |
1540 | |
1541 // Copyright 2007-2010 Baptiste Lepilleur | |
1542 // Distributed under MIT license, or public domain if desired and | |
1543 // recognized in your jurisdiction. | |
1544 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | |
1545 | |
1546 #if !defined(JSON_IS_AMALGAMATION) | |
1547 # include <json/value.h> | |
1548 # include <json/writer.h> | |
1549 # ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | |
1550 # include "json_batchallocator.h" | |
1551 # endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | |
1552 #endif // if !defined(JSON_IS_AMALGAMATION) | |
1553 #include <iostream> | |
1554 #include <utility> | |
1555 #include <stdexcept> | |
1556 #include <cstring> | |
1557 #include <cassert> | |
1558 #ifdef JSON_USE_CPPTL | |
1559 # include <cpptl/conststring.h> | |
1560 #endif | |
1561 #include <cstddef> // size_t | |
1562 | |
1563 #define JSON_ASSERT_UNREACHABLE assert( false ) | |
1564 #define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw | |
1565 #define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message ); | |
1566 #define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) JSON_FAIL_MESSAGE( message ) | |
1567 | |
1568 namespace Json { | |
1569 | |
1570 const Value Value::null; | |
1571 const Int Value::minInt = Int( ~(UInt(-1)/2) ); | |
1572 const Int Value::maxInt = Int( UInt(-1)/2 ); | |
1573 const UInt Value::maxUInt = UInt(-1); | |
1574 const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) ); | |
1575 const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 ); | |
1576 const UInt64 Value::maxUInt64 = UInt64(-1); | |
1577 const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) ); | |
1578 const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 ); | |
1579 const LargestUInt Value::maxLargestUInt = LargestUInt(-1); | |
1580 | |
1581 | |
1582 /// Unknown size marker | |
1583 static const unsigned int unknown = (unsigned)-1; | |
1584 | |
1585 | |
1586 /** Duplicates the specified string value. | |
1587 * @param value Pointer to the string to duplicate. Must be zero-terminated if | |
1588 * length is "unknown". | |
1589 * @param length Length of the value. if equals to unknown, then it will be | |
1590 * computed using strlen(value). | |
1591 * @return Pointer on the duplicate instance of string. | |
1592 */ | |
1593 static inline char * | |
1594 duplicateStringValue( const char *value, | |
1595 unsigned int length = unknown ) | |
1596 { | |
1597 if ( length == unknown ) | |
1598 length = (unsigned int)strlen(value); | |
1599 char *newString = static_cast<char *>( malloc( length + 1 ) ); | |
1600 JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" ); | |
1601 memcpy( newString, value, length ); | |
1602 newString[length] = 0; | |
1603 return newString; | |
1604 } | |
1605 | |
1606 | |
1607 /** Free the string duplicated by duplicateStringValue(). | |
1608 */ | |
1609 static inline void | |
1610 releaseStringValue( char *value ) | |
1611 { | |
1612 if ( value ) | |
1613 free( value ); | |
1614 } | |
1615 | |
1616 } // namespace Json | |
1617 | |
1618 | |
1619 // ////////////////////////////////////////////////////////////////// | |
1620 // ////////////////////////////////////////////////////////////////// | |
1621 // ////////////////////////////////////////////////////////////////// | |
1622 // ValueInternals... | |
1623 // ////////////////////////////////////////////////////////////////// | |
1624 // ////////////////////////////////////////////////////////////////// | |
1625 // ////////////////////////////////////////////////////////////////// | |
1626 #if !defined(JSON_IS_AMALGAMATION) | |
1627 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1628 # include "json_internalarray.inl" | |
1629 # include "json_internalmap.inl" | |
1630 # endif // JSON_VALUE_USE_INTERNAL_MAP | |
1631 | |
1632 # include "json_valueiterator.inl" | |
1633 #endif // if !defined(JSON_IS_AMALGAMATION) | |
1634 | |
1635 namespace Json { | |
1636 | |
1637 // ////////////////////////////////////////////////////////////////// | |
1638 // ////////////////////////////////////////////////////////////////// | |
1639 // ////////////////////////////////////////////////////////////////// | |
1640 // class Value::CommentInfo | |
1641 // ////////////////////////////////////////////////////////////////// | |
1642 // ////////////////////////////////////////////////////////////////// | |
1643 // ////////////////////////////////////////////////////////////////// | |
1644 | |
1645 | |
1646 Value::CommentInfo::CommentInfo() | |
1647 : comment_( 0 ) | |
1648 { | |
1649 } | |
1650 | |
1651 Value::CommentInfo::~CommentInfo() | |
1652 { | |
1653 if ( comment_ ) | |
1654 releaseStringValue( comment_ ); | |
1655 } | |
1656 | |
1657 | |
1658 void | |
1659 Value::CommentInfo::setComment( const char *text ) | |
1660 { | |
1661 if ( comment_ ) | |
1662 releaseStringValue( comment_ ); | |
1663 JSON_ASSERT( text != 0 ); | |
1664 JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); | |
1665 // It seems that /**/ style comments are acceptable as well. | |
1666 comment_ = duplicateStringValue( text ); | |
1667 } | |
1668 | |
1669 | |
1670 // ////////////////////////////////////////////////////////////////// | |
1671 // ////////////////////////////////////////////////////////////////// | |
1672 // ////////////////////////////////////////////////////////////////// | |
1673 // class Value::CZString | |
1674 // ////////////////////////////////////////////////////////////////// | |
1675 // ////////////////////////////////////////////////////////////////// | |
1676 // ////////////////////////////////////////////////////////////////// | |
1677 # ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1678 | |
1679 // Notes: index_ indicates if the string was allocated when | |
1680 // a string is stored. | |
1681 | |
1682 Value::CZString::CZString( ArrayIndex index ) | |
1683 : cstr_( 0 ) | |
1684 , index_( index ) | |
1685 { | |
1686 } | |
1687 | |
1688 Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) | |
1689 : cstr_( allocate == duplicate ? duplicateStringValue(cstr) | |
1690 : cstr ) | |
1691 , index_( allocate ) | |
1692 { | |
1693 } | |
1694 | |
1695 Value::CZString::CZString( const CZString &other ) | |
1696 : cstr_( other.index_ != noDuplication && other.cstr_ != 0 | |
1697 ? duplicateStringValue( other.cstr_ ) | |
1698 : other.cstr_ ) | |
1699 , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) | |
1700 : other.index_ ) | |
1701 { | |
1702 } | |
1703 | |
1704 Value::CZString::~CZString() | |
1705 { | |
1706 if ( cstr_ && index_ == duplicate ) | |
1707 releaseStringValue( const_cast<char *>( cstr_ ) ); | |
1708 } | |
1709 | |
1710 void | |
1711 Value::CZString::swap( CZString &other ) | |
1712 { | |
1713 std::swap( cstr_, other.cstr_ ); | |
1714 std::swap( index_, other.index_ ); | |
1715 } | |
1716 | |
1717 Value::CZString & | |
1718 Value::CZString::operator =( const CZString &other ) | |
1719 { | |
1720 CZString temp( other ); | |
1721 swap( temp ); | |
1722 return *this; | |
1723 } | |
1724 | |
1725 bool | |
1726 Value::CZString::operator<( const CZString &other ) const | |
1727 { | |
1728 if ( cstr_ ) | |
1729 return strcmp( cstr_, other.cstr_ ) < 0; | |
1730 return index_ < other.index_; | |
1731 } | |
1732 | |
1733 bool | |
1734 Value::CZString::operator==( const CZString &other ) const | |
1735 { | |
1736 if ( cstr_ ) | |
1737 return strcmp( cstr_, other.cstr_ ) == 0; | |
1738 return index_ == other.index_; | |
1739 } | |
1740 | |
1741 | |
1742 ArrayIndex | |
1743 Value::CZString::index() const | |
1744 { | |
1745 return index_; | |
1746 } | |
1747 | |
1748 | |
1749 const char * | |
1750 Value::CZString::c_str() const | |
1751 { | |
1752 return cstr_; | |
1753 } | |
1754 | |
1755 bool | |
1756 Value::CZString::isStaticString() const | |
1757 { | |
1758 return index_ == noDuplication; | |
1759 } | |
1760 | |
1761 #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1762 | |
1763 | |
1764 // ////////////////////////////////////////////////////////////////// | |
1765 // ////////////////////////////////////////////////////////////////// | |
1766 // ////////////////////////////////////////////////////////////////// | |
1767 // class Value::Value | |
1768 // ////////////////////////////////////////////////////////////////// | |
1769 // ////////////////////////////////////////////////////////////////// | |
1770 // ////////////////////////////////////////////////////////////////// | |
1771 | |
1772 /*! \internal Default constructor initialization must be equivalent to: | |
1773 * memset( this, 0, sizeof(Value) ) | |
1774 * This optimization is used in ValueInternalMap fast allocator. | |
1775 */ | |
1776 Value::Value( ValueType type ) | |
1777 : type_( type ) | |
1778 , allocated_( 0 ) | |
1779 , comments_( 0 ) | |
1780 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1781 , itemIsUsed_( 0 ) | |
1782 #endif | |
1783 { | |
1784 switch ( type ) | |
1785 { | |
1786 case nullValue: | |
1787 break; | |
1788 case intValue: | |
1789 case uintValue: | |
1790 value_.int_ = 0; | |
1791 break; | |
1792 case realValue: | |
1793 value_.real_ = 0.0; | |
1794 break; | |
1795 case stringValue: | |
1796 value_.string_ = 0; | |
1797 break; | |
1798 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1799 case arrayValue: | |
1800 case objectValue: | |
1801 value_.map_ = new ObjectValues(); | |
1802 break; | |
1803 #else | |
1804 case arrayValue: | |
1805 value_.array_ = arrayAllocator()->newArray(); | |
1806 break; | |
1807 case objectValue: | |
1808 value_.map_ = mapAllocator()->newMap(); | |
1809 break; | |
1810 #endif | |
1811 case booleanValue: | |
1812 value_.bool_ = false; | |
1813 break; | |
1814 default: | |
1815 JSON_ASSERT_UNREACHABLE; | |
1816 } | |
1817 } | |
1818 | |
1819 | |
1820 #if defined(JSON_HAS_INT64) | |
1821 Value::Value( UInt value ) | |
1822 : type_( uintValue ) | |
1823 , comments_( 0 ) | |
1824 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1825 , itemIsUsed_( 0 ) | |
1826 #endif | |
1827 { | |
1828 value_.uint_ = value; | |
1829 } | |
1830 | |
1831 Value::Value( Int value ) | |
1832 : type_( intValue ) | |
1833 , comments_( 0 ) | |
1834 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1835 , itemIsUsed_( 0 ) | |
1836 #endif | |
1837 { | |
1838 value_.int_ = value; | |
1839 } | |
1840 | |
1841 #endif // if defined(JSON_HAS_INT64) | |
1842 | |
1843 | |
1844 Value::Value( Int64 value ) | |
1845 : type_( intValue ) | |
1846 , comments_( 0 ) | |
1847 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1848 , itemIsUsed_( 0 ) | |
1849 #endif | |
1850 { | |
1851 value_.int_ = value; | |
1852 } | |
1853 | |
1854 | |
1855 Value::Value( UInt64 value ) | |
1856 : type_( uintValue ) | |
1857 , comments_( 0 ) | |
1858 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1859 , itemIsUsed_( 0 ) | |
1860 #endif | |
1861 { | |
1862 value_.uint_ = value; | |
1863 } | |
1864 | |
1865 Value::Value( double value ) | |
1866 : type_( realValue ) | |
1867 , comments_( 0 ) | |
1868 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1869 , itemIsUsed_( 0 ) | |
1870 #endif | |
1871 { | |
1872 value_.real_ = value; | |
1873 } | |
1874 | |
1875 Value::Value( const char *value ) | |
1876 : type_( stringValue ) | |
1877 , allocated_( true ) | |
1878 , comments_( 0 ) | |
1879 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1880 , itemIsUsed_( 0 ) | |
1881 #endif | |
1882 { | |
1883 value_.string_ = duplicateStringValue( value ); | |
1884 } | |
1885 | |
1886 | |
1887 Value::Value( const char *beginValue, | |
1888 const char *endValue ) | |
1889 : type_( stringValue ) | |
1890 , allocated_( true ) | |
1891 , comments_( 0 ) | |
1892 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1893 , itemIsUsed_( 0 ) | |
1894 #endif | |
1895 { | |
1896 value_.string_ = duplicateStringValue( beginValue, | |
1897 (unsigned int)(endValue - beginValue) ); | |
1898 } | |
1899 | |
1900 | |
1901 Value::Value( const std::string &value ) | |
1902 : type_( stringValue ) | |
1903 , allocated_( true ) | |
1904 , comments_( 0 ) | |
1905 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1906 , itemIsUsed_( 0 ) | |
1907 #endif | |
1908 { | |
1909 value_.string_ = duplicateStringValue( value.c_str(), | |
1910 (unsigned int)value.length() ); | |
1911 | |
1912 } | |
1913 | |
1914 Value::Value( const StaticString &value ) | |
1915 : type_( stringValue ) | |
1916 , allocated_( false ) | |
1917 , comments_( 0 ) | |
1918 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1919 , itemIsUsed_( 0 ) | |
1920 #endif | |
1921 { | |
1922 value_.string_ = const_cast<char *>( value.c_str() ); | |
1923 } | |
1924 | |
1925 | |
1926 # ifdef JSON_USE_CPPTL | |
1927 Value::Value( const CppTL::ConstString &value ) | |
1928 : type_( stringValue ) | |
1929 , allocated_( true ) | |
1930 , comments_( 0 ) | |
1931 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1932 , itemIsUsed_( 0 ) | |
1933 #endif | |
1934 { | |
1935 value_.string_ = duplicateStringValue( value, value.length() ); | |
1936 } | |
1937 # endif | |
1938 | |
1939 Value::Value( bool value ) | |
1940 : type_( booleanValue ) | |
1941 , comments_( 0 ) | |
1942 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1943 , itemIsUsed_( 0 ) | |
1944 #endif | |
1945 { | |
1946 value_.bool_ = value; | |
1947 } | |
1948 | |
1949 | |
1950 Value::Value( const Value &other ) | |
1951 : type_( other.type_ ) | |
1952 , comments_( 0 ) | |
1953 # ifdef JSON_VALUE_USE_INTERNAL_MAP | |
1954 , itemIsUsed_( 0 ) | |
1955 #endif | |
1956 { | |
1957 switch ( type_ ) | |
1958 { | |
1959 case nullValue: | |
1960 case intValue: | |
1961 case uintValue: | |
1962 case realValue: | |
1963 case booleanValue: | |
1964 value_ = other.value_; | |
1965 break; | |
1966 case stringValue: | |
1967 if ( other.value_.string_ ) | |
1968 { | |
1969 value_.string_ = duplicateStringValue( other.value_.string_ ); | |
1970 allocated_ = true; | |
1971 } | |
1972 else | |
1973 value_.string_ = 0; | |
1974 break; | |
1975 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
1976 case arrayValue: | |
1977 case objectValue: | |
1978 value_.map_ = new ObjectValues( *other.value_.map_ ); | |
1979 break; | |
1980 #else | |
1981 case arrayValue: | |
1982 value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); | |
1983 break; | |
1984 case objectValue: | |
1985 value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); | |
1986 break; | |
1987 #endif | |
1988 default: | |
1989 JSON_ASSERT_UNREACHABLE; | |
1990 } | |
1991 if ( other.comments_ ) | |
1992 { | |
1993 comments_ = new CommentInfo[numberOfCommentPlacement]; | |
1994 for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) | |
1995 { | |
1996 const CommentInfo &otherComment = other.comments_[comment]; | |
1997 if ( otherComment.comment_ ) | |
1998 comments_[comment].setComment( otherComment.comment_ ); | |
1999 } | |
2000 } | |
2001 } | |
2002 | |
2003 | |
2004 Value::~Value() | |
2005 { | |
2006 switch ( type_ ) | |
2007 { | |
2008 case nullValue: | |
2009 case intValue: | |
2010 case uintValue: | |
2011 case realValue: | |
2012 case booleanValue: | |
2013 break; | |
2014 case stringValue: | |
2015 if ( allocated_ ) | |
2016 releaseStringValue( value_.string_ ); | |
2017 break; | |
2018 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2019 case arrayValue: | |
2020 case objectValue: | |
2021 delete value_.map_; | |
2022 break; | |
2023 #else | |
2024 case arrayValue: | |
2025 arrayAllocator()->destructArray( value_.array_ ); | |
2026 break; | |
2027 case objectValue: | |
2028 mapAllocator()->destructMap( value_.map_ ); | |
2029 break; | |
2030 #endif | |
2031 default: | |
2032 JSON_ASSERT_UNREACHABLE; | |
2033 } | |
2034 | |
2035 if ( comments_ ) | |
2036 delete[] comments_; | |
2037 } | |
2038 | |
2039 Value & | |
2040 Value::operator=( const Value &other ) | |
2041 { | |
2042 Value temp( other ); | |
2043 swap( temp ); | |
2044 return *this; | |
2045 } | |
2046 | |
2047 void | |
2048 Value::swap( Value &other ) | |
2049 { | |
2050 ValueType temp = type_; | |
2051 type_ = other.type_; | |
2052 other.type_ = temp; | |
2053 std::swap( value_, other.value_ ); | |
2054 int temp2 = allocated_; | |
2055 allocated_ = other.allocated_; | |
2056 other.allocated_ = temp2; | |
2057 } | |
2058 | |
2059 ValueType | |
2060 Value::type() const | |
2061 { | |
2062 return type_; | |
2063 } | |
2064 | |
2065 | |
2066 int | |
2067 Value::compare( const Value &other ) const | |
2068 { | |
2069 if ( *this < other ) | |
2070 return -1; | |
2071 if ( *this > other ) | |
2072 return 1; | |
2073 return 0; | |
2074 } | |
2075 | |
2076 | |
2077 bool | |
2078 Value::operator <( const Value &other ) const | |
2079 { | |
2080 int typeDelta = type_ - other.type_; | |
2081 if ( typeDelta ) | |
2082 return typeDelta < 0 ? true : false; | |
2083 switch ( type_ ) | |
2084 { | |
2085 case nullValue: | |
2086 return false; | |
2087 case intValue: | |
2088 return value_.int_ < other.value_.int_; | |
2089 case uintValue: | |
2090 return value_.uint_ < other.value_.uint_; | |
2091 case realValue: | |
2092 return value_.real_ < other.value_.real_; | |
2093 case booleanValue: | |
2094 return value_.bool_ < other.value_.bool_; | |
2095 case stringValue: | |
2096 return ( value_.string_ == 0 && other.value_.string_ ) | |
2097 || ( other.value_.string_ | |
2098 && value_.string_ | |
2099 && strcmp( value_.string_, other.value_.string_ ) < 0 ); | |
2100 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2101 case arrayValue: | |
2102 case objectValue: | |
2103 { | |
2104 int delta = int( value_.map_->size() - other.value_.map_->size() ); | |
2105 if ( delta ) | |
2106 return delta < 0; | |
2107 return (*value_.map_) < (*other.value_.map_); | |
2108 } | |
2109 #else | |
2110 case arrayValue: | |
2111 return value_.array_->compare( *(other.value_.array_) ) < 0; | |
2112 case objectValue: | |
2113 return value_.map_->compare( *(other.value_.map_) ) < 0; | |
2114 #endif | |
2115 default: | |
2116 JSON_ASSERT_UNREACHABLE; | |
2117 } | |
2118 return false; // unreachable | |
2119 } | |
2120 | |
2121 bool | |
2122 Value::operator <=( const Value &other ) const | |
2123 { | |
2124 return !(other < *this); | |
2125 } | |
2126 | |
2127 bool | |
2128 Value::operator >=( const Value &other ) const | |
2129 { | |
2130 return !(*this < other); | |
2131 } | |
2132 | |
2133 bool | |
2134 Value::operator >( const Value &other ) const | |
2135 { | |
2136 return other < *this; | |
2137 } | |
2138 | |
2139 bool | |
2140 Value::operator ==( const Value &other ) const | |
2141 { | |
2142 //if ( type_ != other.type_ ) | |
2143 // GCC 2.95.3 says: | |
2144 // attempt to take address of bit-field structure member `Json::Value::type_' | |
2145 // Beats me, but a temp solves the problem. | |
2146 int temp = other.type_; | |
2147 if ( type_ != temp ) | |
2148 return false; | |
2149 switch ( type_ ) | |
2150 { | |
2151 case nullValue: | |
2152 return true; | |
2153 case intValue: | |
2154 return value_.int_ == other.value_.int_; | |
2155 case uintValue: | |
2156 return value_.uint_ == other.value_.uint_; | |
2157 case realValue: | |
2158 return value_.real_ == other.value_.real_; | |
2159 case booleanValue: | |
2160 return value_.bool_ == other.value_.bool_; | |
2161 case stringValue: | |
2162 return ( value_.string_ == other.value_.string_ ) | |
2163 || ( other.value_.string_ | |
2164 && value_.string_ | |
2165 && strcmp( value_.string_, other.value_.string_ ) == 0 ); | |
2166 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2167 case arrayValue: | |
2168 case objectValue: | |
2169 return value_.map_->size() == other.value_.map_->size() | |
2170 && (*value_.map_) == (*other.value_.map_); | |
2171 #else | |
2172 case arrayValue: | |
2173 return value_.array_->compare( *(other.value_.array_) ) == 0; | |
2174 case objectValue: | |
2175 return value_.map_->compare( *(other.value_.map_) ) == 0; | |
2176 #endif | |
2177 default: | |
2178 JSON_ASSERT_UNREACHABLE; | |
2179 } | |
2180 return false; // unreachable | |
2181 } | |
2182 | |
2183 bool | |
2184 Value::operator !=( const Value &other ) const | |
2185 { | |
2186 return !( *this == other ); | |
2187 } | |
2188 | |
2189 const char * | |
2190 Value::asCString() const | |
2191 { | |
2192 JSON_ASSERT( type_ == stringValue ); | |
2193 return value_.string_; | |
2194 } | |
2195 | |
2196 | |
2197 std::string | |
2198 Value::asString() const | |
2199 { | |
2200 switch ( type_ ) | |
2201 { | |
2202 case nullValue: | |
2203 return ""; | |
2204 case stringValue: | |
2205 return value_.string_ ? value_.string_ : ""; | |
2206 case booleanValue: | |
2207 return value_.bool_ ? "true" : "false"; | |
2208 case intValue: | |
2209 case uintValue: | |
2210 case realValue: | |
2211 case arrayValue: | |
2212 case objectValue: | |
2213 JSON_FAIL_MESSAGE( "Type is not convertible to string" ); | |
2214 default: | |
2215 JSON_ASSERT_UNREACHABLE; | |
2216 } | |
2217 return ""; // unreachable | |
2218 } | |
2219 | |
2220 # ifdef JSON_USE_CPPTL | |
2221 CppTL::ConstString | |
2222 Value::asConstString() const | |
2223 { | |
2224 return CppTL::ConstString( asString().c_str() ); | |
2225 } | |
2226 # endif | |
2227 | |
2228 | |
2229 Value::Int | |
2230 Value::asInt() const | |
2231 { | |
2232 switch ( type_ ) | |
2233 { | |
2234 case nullValue: | |
2235 return 0; | |
2236 case intValue: | |
2237 JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" ); | |
2238 return Int(value_.int_); | |
2239 case uintValue: | |
2240 JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" ); | |
2241 return Int(value_.uint_); | |
2242 case realValue: | |
2243 JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); | |
2244 return Int( value_.real_ ); | |
2245 case booleanValue: | |
2246 return value_.bool_ ? 1 : 0; | |
2247 case stringValue: | |
2248 case arrayValue: | |
2249 case objectValue: | |
2250 JSON_FAIL_MESSAGE( "Type is not convertible to int" ); | |
2251 default: | |
2252 JSON_ASSERT_UNREACHABLE; | |
2253 } | |
2254 return 0; // unreachable; | |
2255 } | |
2256 | |
2257 | |
2258 Value::UInt | |
2259 Value::asUInt() const | |
2260 { | |
2261 switch ( type_ ) | |
2262 { | |
2263 case nullValue: | |
2264 return 0; | |
2265 case intValue: | |
2266 JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); | |
2267 JSON_ASSERT_MESSAGE( value_.int_ <= maxUInt, "signed integer out of UInt range" ); | |
2268 return UInt(value_.int_); | |
2269 case uintValue: | |
2270 JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" ); | |
2271 return UInt(value_.uint_); | |
2272 case realValue: | |
2273 JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); | |
2274 return UInt( value_.real_ ); | |
2275 case booleanValue: | |
2276 return value_.bool_ ? 1 : 0; | |
2277 case stringValue: | |
2278 case arrayValue: | |
2279 case objectValue: | |
2280 JSON_FAIL_MESSAGE( "Type is not convertible to uint" ); | |
2281 default: | |
2282 JSON_ASSERT_UNREACHABLE; | |
2283 } | |
2284 return 0; // unreachable; | |
2285 } | |
2286 | |
2287 | |
2288 # if defined(JSON_HAS_INT64) | |
2289 | |
2290 Value::Int64 | |
2291 Value::asInt64() const | |
2292 { | |
2293 switch ( type_ ) | |
2294 { | |
2295 case nullValue: | |
2296 return 0; | |
2297 case intValue: | |
2298 return value_.int_; | |
2299 case uintValue: | |
2300 JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" ); | |
2301 return value_.uint_; | |
2302 case realValue: | |
2303 JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" ); | |
2304 return Int( value_.real_ ); | |
2305 case booleanValue: | |
2306 return value_.bool_ ? 1 : 0; | |
2307 case stringValue: | |
2308 case arrayValue: | |
2309 case objectValue: | |
2310 JSON_FAIL_MESSAGE( "Type is not convertible to Int64" ); | |
2311 default: | |
2312 JSON_ASSERT_UNREACHABLE; | |
2313 } | |
2314 return 0; // unreachable; | |
2315 } | |
2316 | |
2317 | |
2318 Value::UInt64 | |
2319 Value::asUInt64() const | |
2320 { | |
2321 switch ( type_ ) | |
2322 { | |
2323 case nullValue: | |
2324 return 0; | |
2325 case intValue: | |
2326 JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" ); | |
2327 return value_.int_; | |
2328 case uintValue: | |
2329 return value_.uint_; | |
2330 case realValue: | |
2331 JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" ); | |
2332 return UInt( value_.real_ ); | |
2333 case booleanValue: | |
2334 return value_.bool_ ? 1 : 0; | |
2335 case stringValue: | |
2336 case arrayValue: | |
2337 case objectValue: | |
2338 JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" ); | |
2339 default: | |
2340 JSON_ASSERT_UNREACHABLE; | |
2341 } | |
2342 return 0; // unreachable; | |
2343 } | |
2344 # endif // if defined(JSON_HAS_INT64) | |
2345 | |
2346 | |
2347 LargestInt | |
2348 Value::asLargestInt() const | |
2349 { | |
2350 #if defined(JSON_NO_INT64) | |
2351 return asInt(); | |
2352 #else | |
2353 return asInt64(); | |
2354 #endif | |
2355 } | |
2356 | |
2357 | |
2358 LargestUInt | |
2359 Value::asLargestUInt() const | |
2360 { | |
2361 #if defined(JSON_NO_INT64) | |
2362 return asUInt(); | |
2363 #else | |
2364 return asUInt64(); | |
2365 #endif | |
2366 } | |
2367 | |
2368 | |
2369 double | |
2370 Value::asDouble() const | |
2371 { | |
2372 switch ( type_ ) | |
2373 { | |
2374 case nullValue: | |
2375 return 0.0; | |
2376 case intValue: | |
2377 return static_cast<double>( value_.int_ ); | |
2378 case uintValue: | |
2379 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) | |
2380 return static_cast<double>( value_.uint_ ); | |
2381 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) | |
2382 return static_cast<double>( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); | |
2383 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) | |
2384 case realValue: | |
2385 return value_.real_; | |
2386 case booleanValue: | |
2387 return value_.bool_ ? 1.0 : 0.0; | |
2388 case stringValue: | |
2389 case arrayValue: | |
2390 case objectValue: | |
2391 JSON_FAIL_MESSAGE( "Type is not convertible to double" ); | |
2392 default: | |
2393 JSON_ASSERT_UNREACHABLE; | |
2394 } | |
2395 return 0; // unreachable; | |
2396 } | |
2397 | |
2398 float | |
2399 Value::asFloat() const | |
2400 { | |
2401 switch ( type_ ) | |
2402 { | |
2403 case nullValue: | |
2404 return 0.0f; | |
2405 case intValue: | |
2406 return static_cast<float>( value_.int_ ); | |
2407 case uintValue: | |
2408 #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) | |
2409 return static_cast<float>( value_.uint_ ); | |
2410 #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) | |
2411 return static_cast<float>( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); | |
2412 #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) | |
2413 case realValue: | |
2414 return static_cast<float>( value_.real_ ); | |
2415 case booleanValue: | |
2416 return value_.bool_ ? 1.0f : 0.0f; | |
2417 case stringValue: | |
2418 case arrayValue: | |
2419 case objectValue: | |
2420 JSON_FAIL_MESSAGE( "Type is not convertible to float" ); | |
2421 default: | |
2422 JSON_ASSERT_UNREACHABLE; | |
2423 } | |
2424 return 0.0f; // unreachable; | |
2425 } | |
2426 | |
2427 bool | |
2428 Value::asBool() const | |
2429 { | |
2430 switch ( type_ ) | |
2431 { | |
2432 case nullValue: | |
2433 return false; | |
2434 case intValue: | |
2435 case uintValue: | |
2436 return value_.int_ != 0; | |
2437 case realValue: | |
2438 return value_.real_ != 0.0; | |
2439 case booleanValue: | |
2440 return value_.bool_; | |
2441 case stringValue: | |
2442 return value_.string_ && value_.string_[0] != 0; | |
2443 case arrayValue: | |
2444 case objectValue: | |
2445 return value_.map_->size() != 0; | |
2446 default: | |
2447 JSON_ASSERT_UNREACHABLE; | |
2448 } | |
2449 return false; // unreachable; | |
2450 } | |
2451 | |
2452 | |
2453 bool | |
2454 Value::isConvertibleTo( ValueType other ) const | |
2455 { | |
2456 switch ( type_ ) | |
2457 { | |
2458 case nullValue: | |
2459 return true; | |
2460 case intValue: | |
2461 return ( other == nullValue && value_.int_ == 0 ) | |
2462 || other == intValue | |
2463 || ( other == uintValue && value_.int_ >= 0 ) | |
2464 || other == realValue | |
2465 || other == stringValue | |
2466 || other == booleanValue; | |
2467 case uintValue: | |
2468 return ( other == nullValue && value_.uint_ == 0 ) | |
2469 || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) | |
2470 || other == uintValue | |
2471 || other == realValue | |
2472 || other == stringValue | |
2473 || other == booleanValue; | |
2474 case realValue: | |
2475 return ( other == nullValue && value_.real_ == 0.0 ) | |
2476 || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) | |
2477 || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) | |
2478 || other == realValue | |
2479 || other == stringValue | |
2480 || other == booleanValue; | |
2481 case booleanValue: | |
2482 return ( other == nullValue && value_.bool_ == false ) | |
2483 || other == intValue | |
2484 || other == uintValue | |
2485 || other == realValue | |
2486 || other == stringValue | |
2487 || other == booleanValue; | |
2488 case stringValue: | |
2489 return other == stringValue | |
2490 || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); | |
2491 case arrayValue: | |
2492 return other == arrayValue | |
2493 || ( other == nullValue && value_.map_->size() == 0 ); | |
2494 case objectValue: | |
2495 return other == objectValue | |
2496 || ( other == nullValue && value_.map_->size() == 0 ); | |
2497 default: | |
2498 JSON_ASSERT_UNREACHABLE; | |
2499 } | |
2500 return false; // unreachable; | |
2501 } | |
2502 | |
2503 | |
2504 /// Number of values in array or object | |
2505 ArrayIndex | |
2506 Value::size() const | |
2507 { | |
2508 switch ( type_ ) | |
2509 { | |
2510 case nullValue: | |
2511 case intValue: | |
2512 case uintValue: | |
2513 case realValue: | |
2514 case booleanValue: | |
2515 case stringValue: | |
2516 return 0; | |
2517 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2518 case arrayValue: // size of the array is highest index + 1 | |
2519 if ( !value_.map_->empty() ) | |
2520 { | |
2521 ObjectValues::const_iterator itLast = value_.map_->end(); | |
2522 --itLast; | |
2523 return (*itLast).first.index()+1; | |
2524 } | |
2525 return 0; | |
2526 case objectValue: | |
2527 return ArrayIndex( value_.map_->size() ); | |
2528 #else | |
2529 case arrayValue: | |
2530 return Int( value_.array_->size() ); | |
2531 case objectValue: | |
2532 return Int( value_.map_->size() ); | |
2533 #endif | |
2534 default: | |
2535 JSON_ASSERT_UNREACHABLE; | |
2536 } | |
2537 return 0; // unreachable; | |
2538 } | |
2539 | |
2540 | |
2541 bool | |
2542 Value::empty() const | |
2543 { | |
2544 if ( isNull() || isArray() || isObject() ) | |
2545 return size() == 0u; | |
2546 else | |
2547 return false; | |
2548 } | |
2549 | |
2550 | |
2551 bool | |
2552 Value::operator!() const | |
2553 { | |
2554 return isNull(); | |
2555 } | |
2556 | |
2557 | |
2558 void | |
2559 Value::clear() | |
2560 { | |
2561 JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); | |
2562 | |
2563 switch ( type_ ) | |
2564 { | |
2565 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2566 case arrayValue: | |
2567 case objectValue: | |
2568 value_.map_->clear(); | |
2569 break; | |
2570 #else | |
2571 case arrayValue: | |
2572 value_.array_->clear(); | |
2573 break; | |
2574 case objectValue: | |
2575 value_.map_->clear(); | |
2576 break; | |
2577 #endif | |
2578 default: | |
2579 break; | |
2580 } | |
2581 } | |
2582 | |
2583 void | |
2584 Value::resize( ArrayIndex newSize ) | |
2585 { | |
2586 JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); | |
2587 if ( type_ == nullValue ) | |
2588 *this = Value( arrayValue ); | |
2589 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2590 ArrayIndex oldSize = size(); | |
2591 if ( newSize == 0 ) | |
2592 clear(); | |
2593 else if ( newSize > oldSize ) | |
2594 (*this)[ newSize - 1 ]; | |
2595 else | |
2596 { | |
2597 for ( ArrayIndex index = newSize; index < oldSize; ++index ) | |
2598 { | |
2599 value_.map_->erase( index ); | |
2600 } | |
2601 assert( size() == newSize ); | |
2602 } | |
2603 #else | |
2604 value_.array_->resize( newSize ); | |
2605 #endif | |
2606 } | |
2607 | |
2608 | |
2609 Value & | |
2610 Value::operator[]( ArrayIndex index ) | |
2611 { | |
2612 JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); | |
2613 if ( type_ == nullValue ) | |
2614 *this = Value( arrayValue ); | |
2615 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2616 CZString key( index ); | |
2617 ObjectValues::iterator it = value_.map_->lower_bound( key ); | |
2618 if ( it != value_.map_->end() && (*it).first == key ) | |
2619 return (*it).second; | |
2620 | |
2621 ObjectValues::value_type defaultValue( key, null ); | |
2622 it = value_.map_->insert( it, defaultValue ); | |
2623 return (*it).second; | |
2624 #else | |
2625 return value_.array_->resolveReference( index ); | |
2626 #endif | |
2627 } | |
2628 | |
2629 | |
2630 Value & | |
2631 Value::operator[]( int index ) | |
2632 { | |
2633 JSON_ASSERT( index >= 0 ); | |
2634 return (*this)[ ArrayIndex(index) ]; | |
2635 } | |
2636 | |
2637 | |
2638 const Value & | |
2639 Value::operator[]( ArrayIndex index ) const | |
2640 { | |
2641 JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); | |
2642 if ( type_ == nullValue ) | |
2643 return null; | |
2644 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2645 CZString key( index ); | |
2646 ObjectValues::const_iterator it = value_.map_->find( key ); | |
2647 if ( it == value_.map_->end() ) | |
2648 return null; | |
2649 return (*it).second; | |
2650 #else | |
2651 Value *value = value_.array_->find( index ); | |
2652 return value ? *value : null; | |
2653 #endif | |
2654 } | |
2655 | |
2656 | |
2657 const Value & | |
2658 Value::operator[]( int index ) const | |
2659 { | |
2660 JSON_ASSERT( index >= 0 ); | |
2661 return (*this)[ ArrayIndex(index) ]; | |
2662 } | |
2663 | |
2664 | |
2665 Value & | |
2666 Value::operator[]( const char *key ) | |
2667 { | |
2668 return resolveReference( key, false ); | |
2669 } | |
2670 | |
2671 | |
2672 Value & | |
2673 Value::resolveReference( const char *key, | |
2674 bool isStatic ) | |
2675 { | |
2676 JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | |
2677 if ( type_ == nullValue ) | |
2678 *this = Value( objectValue ); | |
2679 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2680 CZString actualKey( key, isStatic ? CZString::noDuplication | |
2681 : CZString::duplicateOnCopy ); | |
2682 ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); | |
2683 if ( it != value_.map_->end() && (*it).first == actualKey ) | |
2684 return (*it).second; | |
2685 | |
2686 ObjectValues::value_type defaultValue( actualKey, null ); | |
2687 it = value_.map_->insert( it, defaultValue ); | |
2688 Value &value = (*it).second; | |
2689 return value; | |
2690 #else | |
2691 return value_.map_->resolveReference( key, isStatic ); | |
2692 #endif | |
2693 } | |
2694 | |
2695 | |
2696 Value | |
2697 Value::get( ArrayIndex index, | |
2698 const Value &defaultValue ) const | |
2699 { | |
2700 const Value *value = &((*this)[index]); | |
2701 return value == &null ? defaultValue : *value; | |
2702 } | |
2703 | |
2704 | |
2705 bool | |
2706 Value::isValidIndex( ArrayIndex index ) const | |
2707 { | |
2708 return index < size(); | |
2709 } | |
2710 | |
2711 | |
2712 | |
2713 const Value & | |
2714 Value::operator[]( const char *key ) const | |
2715 { | |
2716 JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | |
2717 if ( type_ == nullValue ) | |
2718 return null; | |
2719 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2720 CZString actualKey( key, CZString::noDuplication ); | |
2721 ObjectValues::const_iterator it = value_.map_->find( actualKey ); | |
2722 if ( it == value_.map_->end() ) | |
2723 return null; | |
2724 return (*it).second; | |
2725 #else | |
2726 const Value *value = value_.map_->find( key ); | |
2727 return value ? *value : null; | |
2728 #endif | |
2729 } | |
2730 | |
2731 | |
2732 Value & | |
2733 Value::operator[]( const std::string &key ) | |
2734 { | |
2735 return (*this)[ key.c_str() ]; | |
2736 } | |
2737 | |
2738 | |
2739 const Value & | |
2740 Value::operator[]( const std::string &key ) const | |
2741 { | |
2742 return (*this)[ key.c_str() ]; | |
2743 } | |
2744 | |
2745 Value & | |
2746 Value::operator[]( const StaticString &key ) | |
2747 { | |
2748 return resolveReference( key, true ); | |
2749 } | |
2750 | |
2751 | |
2752 # ifdef JSON_USE_CPPTL | |
2753 Value & | |
2754 Value::operator[]( const CppTL::ConstString &key ) | |
2755 { | |
2756 return (*this)[ key.c_str() ]; | |
2757 } | |
2758 | |
2759 | |
2760 const Value & | |
2761 Value::operator[]( const CppTL::ConstString &key ) const | |
2762 { | |
2763 return (*this)[ key.c_str() ]; | |
2764 } | |
2765 # endif | |
2766 | |
2767 | |
2768 Value & | |
2769 Value::append( const Value &value ) | |
2770 { | |
2771 return (*this)[size()] = value; | |
2772 } | |
2773 | |
2774 | |
2775 Value | |
2776 Value::get( const char *key, | |
2777 const Value &defaultValue ) const | |
2778 { | |
2779 const Value *value = &((*this)[key]); | |
2780 return value == &null ? defaultValue : *value; | |
2781 } | |
2782 | |
2783 | |
2784 Value | |
2785 Value::get( const std::string &key, | |
2786 const Value &defaultValue ) const | |
2787 { | |
2788 return get( key.c_str(), defaultValue ); | |
2789 } | |
2790 | |
2791 Value | |
2792 Value::removeMember( const char* key ) | |
2793 { | |
2794 JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | |
2795 if ( type_ == nullValue ) | |
2796 return null; | |
2797 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2798 CZString actualKey( key, CZString::noDuplication ); | |
2799 ObjectValues::iterator it = value_.map_->find( actualKey ); | |
2800 if ( it == value_.map_->end() ) | |
2801 return null; | |
2802 Value old(it->second); | |
2803 value_.map_->erase(it); | |
2804 return old; | |
2805 #else | |
2806 Value *value = value_.map_->find( key ); | |
2807 if (value){ | |
2808 Value old(*value); | |
2809 value_.map_.remove( key ); | |
2810 return old; | |
2811 } else { | |
2812 return null; | |
2813 } | |
2814 #endif | |
2815 } | |
2816 | |
2817 Value | |
2818 Value::removeMember( const std::string &key ) | |
2819 { | |
2820 return removeMember( key.c_str() ); | |
2821 } | |
2822 | |
2823 # ifdef JSON_USE_CPPTL | |
2824 Value | |
2825 Value::get( const CppTL::ConstString &key, | |
2826 const Value &defaultValue ) const | |
2827 { | |
2828 return get( key.c_str(), defaultValue ); | |
2829 } | |
2830 # endif | |
2831 | |
2832 bool | |
2833 Value::isMember( const char *key ) const | |
2834 { | |
2835 const Value *value = &((*this)[key]); | |
2836 return value != &null; | |
2837 } | |
2838 | |
2839 | |
2840 bool | |
2841 Value::isMember( const std::string &key ) const | |
2842 { | |
2843 return isMember( key.c_str() ); | |
2844 } | |
2845 | |
2846 | |
2847 # ifdef JSON_USE_CPPTL | |
2848 bool | |
2849 Value::isMember( const CppTL::ConstString &key ) const | |
2850 { | |
2851 return isMember( key.c_str() ); | |
2852 } | |
2853 #endif | |
2854 | |
2855 Value::Members | |
2856 Value::getMemberNames() const | |
2857 { | |
2858 JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | |
2859 if ( type_ == nullValue ) | |
2860 return Value::Members(); | |
2861 Members members; | |
2862 members.reserve( value_.map_->size() ); | |
2863 #ifndef JSON_VALUE_USE_INTERNAL_MAP | |
2864 ObjectValues::const_iterator it = value_.map_->begin(); | |
2865 ObjectValues::const_iterator itEnd = value_.map_->end(); | |
2866 for ( ; it != itEnd; ++it ) | |
2867 members.push_back( std::string( (*it).first.c_str() ) ); | |
2868 #else | |
2869 ValueInternalMap::IteratorState it; | |
2870 ValueInternalMap::IteratorState itEnd; | |
2871 value_.map_->makeBeginIterator( it ); | |
2872 value_.map_->makeEndIterator( itEnd ); | |
2873 for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) | |
2874 members.push_back( std::string( ValueInternalMap::key( it ) ) ); | |
2875 #endif | |
2876 return members; | |
2877 } | |
2878 // | |
2879 //# ifdef JSON_USE_CPPTL | |
2880 //EnumMemberNames | |
2881 //Value::enumMemberNames() const | |
2882 //{ | |
2883 // if ( type_ == objectValue ) | |
2884 // { | |
2885 // return CppTL::Enum::any( CppTL::Enum::transform( | |
2886 // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), | |
2887 // MemberNamesTransform() ) ); | |
2888 // } | |
2889 // return EnumMemberNames(); | |
2890 //} | |
2891 // | |
2892 // | |
2893 //EnumValues | |
2894 //Value::enumValues() const | |
2895 //{ | |
2896 // if ( type_ == objectValue || type_ == arrayValue ) | |
2897 // return CppTL::Enum::anyValues( *(value_.map_), | |
2898 // CppTL::Type<const Value &>() ); | |
2899 // return EnumValues(); | |
2900 //} | |
2901 // | |
2902 //# endif | |
2903 | |
2904 | |
2905 bool | |
2906 Value::isNull() const | |
2907 { | |
2908 return type_ == nullValue; | |
2909 } | |
2910 | |
2911 | |
2912 bool | |
2913 Value::isBool() const | |
2914 { | |
2915 return type_ == booleanValue; | |
2916 } | |
2917 | |
2918 | |
2919 bool | |
2920 Value::isInt() const | |
2921 { | |
2922 return type_ == intValue; | |
2923 } | |
2924 | |
2925 | |
2926 bool | |
2927 Value::isUInt() const | |
2928 { | |
2929 return type_ == uintValue; | |
2930 } | |
2931 | |
2932 | |
2933 bool | |
2934 Value::isIntegral() const | |
2935 { | |
2936 return type_ == intValue | |
2937 || type_ == uintValue | |
2938 || type_ == booleanValue; | |
2939 } | |
2940 | |
2941 | |
2942 bool | |
2943 Value::isDouble() const | |
2944 { | |
2945 return type_ == realValue; | |
2946 } | |
2947 | |
2948 | |
2949 bool | |
2950 Value::isNumeric() const | |
2951 { | |
2952 return isIntegral() || isDouble(); | |
2953 } | |
2954 | |
2955 | |
2956 bool | |
2957 Value::isString() const | |
2958 { | |
2959 return type_ == stringValue; | |
2960 } | |
2961 | |
2962 | |
2963 bool | |
2964 Value::isArray() const | |
2965 { | |
2966 return type_ == nullValue || type_ == arrayValue; | |
2967 } | |
2968 | |
2969 | |
2970 bool | |
2971 Value::isObject() const | |
2972 { | |
2973 return type_ == nullValue || type_ == objectValue; | |
2974 } | |
2975 | |
2976 | |
2977 void | |
2978 Value::setComment( const char *comment, | |
2979 CommentPlacement placement ) | |
2980 { | |
2981 if ( !comments_ ) | |
2982 comments_ = new CommentInfo[numberOfCommentPlacement]; | |
2983 comments_[placement].setComment( comment ); | |
2984 } | |
2985 | |
2986 | |
2987 void | |
2988 Value::setComment( const std::string &comment, | |
2989 CommentPlacement placement ) | |
2990 { | |
2991 setComment( comment.c_str(), placement ); | |
2992 } | |
2993 | |
2994 | |
2995 bool | |
2996 Value::hasComment( CommentPlacement placement ) const | |
2997 { | |
2998 return comments_ != 0 && comments_[placement].comment_ != 0; | |
2999 } | |
3000 | |
3001 std::string | |
3002 Value::getComment( CommentPlacement placement ) const | |
3003 { | |
3004 if ( hasComment(placement) ) | |
3005 return comments_[placement].comment_; | |
3006 return ""; | |
3007 } | |
3008 | |
3009 | |
3010 std::string | |
3011 Value::toStyledString() const | |
3012 { | |
3013 StyledWriter writer; | |
3014 return writer.write( *this ); | |
3015 } | |
3016 | |
3017 | |
3018 Value::const_iterator | |
3019 Value::begin() const | |
3020 { | |
3021 switch ( type_ ) | |
3022 { | |
3023 #ifdef JSON_VALUE_USE_INTERNAL_MAP | |
3024 case arrayValue: | |
3025 if ( value_.array_ ) | |
3026 { | |
3027 ValueInternalArray::IteratorState it; | |
3028 value_.array_->makeBeginIterator( it ); | |
3029 return const_iterator( it ); | |
3030 } | |
3031 break; | |
3032 case objectValue: | |
3033 if ( value_.map_ ) | |
3034 { | |
3035 ValueInternalMap::IteratorState it; | |
3036 value_.map_->makeBeginIterator( it ); | |
3037 return const_iterator( it ); | |
3038 } | |
3039 break; | |
3040 #else | |
3041 case arrayValue: | |
3042 case objectValue: | |
3043 if ( value_.map_ ) | |
3044 return const_iterator( value_.map_->begin() ); | |
3045 break; | |
3046 #endif | |
3047 default: | |
3048 break; | |
3049 } | |
3050 return const_iterator(); | |
3051 } | |
3052 | |
3053 Value::const_iterator | |
3054 Value::end() const | |
3055 { | |
3056 switch ( type_ ) | |
3057 { | |
3058 #ifdef JSON_VALUE_USE_INTERNAL_MAP | |
3059 case arrayValue: | |
3060 if ( value_.array_ ) | |
3061 { | |
3062 ValueInternalArray::IteratorState it; | |
3063 value_.array_->makeEndIterator( it ); | |
3064 return const_iterator( it ); | |
3065 } | |
3066 break; | |
3067 case objectValue: | |
3068 if ( value_.map_ ) | |
3069 { | |
3070 ValueInternalMap::IteratorState it; | |
3071 value_.map_->makeEndIterator( it ); | |
3072 return const_iterator( it ); | |
3073 } | |
3074 break; | |
3075 #else | |
3076 case arrayValue: | |
3077 case objectValue: | |
3078 if ( value_.map_ ) | |
3079 return const_iterator( value_.map_->end() ); | |
3080 break; | |
3081 #endif | |
3082 default: | |
3083 break; | |
3084 } | |
3085 return const_iterator(); | |
3086 } | |
3087 | |
3088 | |
3089 Value::iterator | |
3090 Value::begin() | |
3091 { | |
3092 switch ( type_ ) | |
3093 { | |
3094 #ifdef JSON_VALUE_USE_INTERNAL_MAP | |
3095 case arrayValue: | |
3096 if ( value_.array_ ) | |
3097 { | |
3098 ValueInternalArray::IteratorState it; | |
3099 value_.array_->makeBeginIterator( it ); | |
3100 return iterator( it ); | |
3101 } | |
3102 break; | |
3103 case objectValue: | |
3104 if ( value_.map_ ) | |
3105 { | |
3106 ValueInternalMap::IteratorState it; | |
3107 value_.map_->makeBeginIterator( it ); | |
3108 return iterator( it ); | |
3109 } | |
3110 break; | |
3111 #else | |
3112 case arrayValue: | |
3113 case objectValue: | |
3114 if ( value_.map_ ) | |
3115 return iterator( value_.map_->begin() ); | |
3116 break; | |
3117 #endif | |
3118 default: | |
3119 break; | |
3120 } | |
3121 return iterator(); | |
3122 } | |
3123 | |
3124 Value::iterator | |
3125 Value::end() | |
3126 { | |
3127 switch ( type_ ) | |
3128 { | |
3129 #ifdef JSON_VALUE_USE_INTERNAL_MAP | |
3130 case arrayValue: | |
3131 if ( value_.array_ ) | |
3132 { | |
3133 ValueInternalArray::IteratorState it; | |
3134 value_.array_->makeEndIterator( it ); | |
3135 return iterator( it ); | |
3136 } | |
3137 break; | |
3138 case objectValue: | |
3139 if ( value_.map_ ) | |
3140 { | |
3141 ValueInternalMap::IteratorState it; | |
3142 value_.map_->makeEndIterator( it ); | |
3143 return iterator( it ); | |
3144 } | |
3145 break; | |
3146 #else | |
3147 case arrayValue: | |
3148 case objectValue: | |
3149 if ( value_.map_ ) | |
3150 return iterator( value_.map_->end() ); | |
3151 break; | |
3152 #endif | |
3153 default: | |
3154 break; | |
3155 } | |
3156 return iterator(); | |
3157 } | |
3158 | |
3159 | |
3160 // class PathArgument | |
3161 // ////////////////////////////////////////////////////////////////// | |
3162 | |
3163 PathArgument::PathArgument() | |
3164 : kind_( kindNone ) | |
3165 { | |
3166 } | |
3167 | |
3168 | |
3169 PathArgument::PathArgument( ArrayIndex index ) | |
3170 : index_( index ) | |
3171 , kind_( kindIndex ) | |
3172 { | |
3173 } | |
3174 | |
3175 | |
3176 PathArgument::PathArgument( const char *key ) | |
3177 : key_( key ) | |
3178 , kind_( kindKey ) | |
3179 { | |
3180 } | |
3181 | |
3182 | |
3183 PathArgument::PathArgument( const std::string &key ) | |
3184 : key_( key.c_str() ) | |
3185 , kind_( kindKey ) | |
3186 { | |
3187 } | |
3188 | |
3189 // class Path | |
3190 // ////////////////////////////////////////////////////////////////// | |
3191 | |
3192 Path::Path( const std::string &path, | |
3193 const PathArgument &a1, | |
3194 const PathArgument &a2, | |
3195 const PathArgument &a3, | |
3196 const PathArgument &a4, | |
3197 const PathArgument &a5 ) | |
3198 { | |
3199 InArgs in; | |
3200 in.push_back( &a1 ); | |
3201 in.push_back( &a2 ); | |
3202 in.push_back( &a3 ); | |
3203 in.push_back( &a4 ); | |
3204 in.push_back( &a5 ); | |
3205 makePath( path, in ); | |
3206 } | |
3207 | |
3208 | |
3209 void | |
3210 Path::makePath( const std::string &path, | |
3211 const InArgs &in ) | |
3212 { | |
3213 const char *current = path.c_str(); | |
3214 const char *end = current + path.length(); | |
3215 InArgs::const_iterator itInArg = in.begin(); | |
3216 while ( current != end ) | |
3217 { | |
3218 if ( *current == '[' ) | |
3219 { | |
3220 ++current; | |
3221 if ( *current == '%' ) | |
3222 addPathInArg( path, in, itInArg, PathArgument::kindIndex ); | |
3223 else | |
3224 { | |
3225 ArrayIndex index = 0; | |
3226 for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) | |
3227 index = index * 10 + ArrayIndex(*current - '0'); | |
3228 args_.push_back( index ); | |
3229 } | |
3230 if ( current == end || *current++ != ']' ) | |
3231 invalidPath( path, int(current - path.c_str()) ); | |
3232 } | |
3233 else if ( *current == '%' ) | |
3234 { | |
3235 addPathInArg( path, in, itInArg, PathArgument::kindKey ); | |
3236 ++current; | |
3237 } | |
3238 else if ( *current == '.' ) | |
3239 { | |
3240 ++current; | |
3241 } | |
3242 else | |
3243 { | |
3244 const char *beginName = current; | |
3245 while ( current != end && !strchr( "[.", *current ) ) | |
3246 ++current; | |
3247 args_.push_back( std::string( beginName, current ) ); | |
3248 } | |
3249 } | |
3250 } | |
3251 | |
3252 | |
3253 void | |
3254 Path::addPathInArg( const std::string &path, | |
3255 const InArgs &in, | |
3256 InArgs::const_iterator &itInArg, | |
3257 PathArgument::Kind kind ) | |
3258 { | |
3259 if ( itInArg == in.end() ) | |
3260 { | |
3261 // Error: missing argument %d | |
3262 } | |
3263 else if ( (*itInArg)->kind_ != kind ) | |
3264 { | |
3265 // Error: bad argument type | |
3266 } | |
3267 else | |
3268 { | |
3269 args_.push_back( **itInArg ); | |
3270 } | |
3271 } | |
3272 | |
3273 | |
3274 void | |
3275 Path::invalidPath( const std::string &path, | |
3276 int location ) | |
3277 { | |
3278 // Error: invalid path. | |
3279 } | |
3280 | |
3281 | |
3282 const Value & | |
3283 Path::resolve( const Value &root ) const | |
3284 { | |
3285 const Value *node = &root; | |
3286 for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) | |
3287 { | |
3288 const PathArgument &arg = *it; | |
3289 if ( arg.kind_ == PathArgument::kindIndex ) | |
3290 { | |
3291 if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) | |
3292 { | |
3293 // Error: unable to resolve path (array value expected at position... | |
3294 } | |
3295 node = &((*node)[arg.index_]); | |
3296 } | |
3297 else if ( arg.kind_ == PathArgument::kindKey ) | |
3298 { | |
3299 if ( !node->isObject() ) | |
3300 { | |
3301 // Error: unable to resolve path (object value expected at position...) | |
3302 } | |
3303 node = &((*node)[arg.key_]); | |
3304 if ( node == &Value::null ) | |
3305 { | |
3306 // Error: unable to resolve path (object has no member named '' at position...) | |
3307 } | |
3308 } | |
3309 } | |
3310 return *node; | |
3311 } | |
3312 | |
3313 | |
3314 Value | |
3315 Path::resolve( const Value &root, | |
3316 const Value &defaultValue ) const | |
3317 { | |
3318 const Value *node = &root; | |
3319 for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) | |
3320 { | |
3321 const PathArgument &arg = *it; | |
3322 if ( arg.kind_ == PathArgument::kindIndex ) | |
3323 { | |
3324 if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) | |
3325 return defaultValue; | |
3326 node = &((*node)[arg.index_]); | |
3327 } | |
3328 else if ( arg.kind_ == PathArgument::kindKey ) | |
3329 { | |
3330 if ( !node->isObject() ) | |
3331 return defaultValue; | |
3332 node = &((*node)[arg.key_]); | |
3333 if ( node == &Value::null ) | |
3334 return defaultValue; | |
3335 } | |
3336 } | |
3337 return *node; | |
3338 } | |
3339 | |
3340 | |
3341 Value & | |
3342 Path::make( Value &root ) const | |
3343 { | |
3344 Value *node = &root; | |
3345 for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) | |
3346 { | |
3347 const PathArgument &arg = *it; | |
3348 if ( arg.kind_ == PathArgument::kindIndex ) | |
3349 { | |
3350 if ( !node->isArray() ) | |
3351 { | |
3352 // Error: node is not an array at position ... | |
3353 } | |
3354 node = &((*node)[arg.index_]); | |
3355 } | |
3356 else if ( arg.kind_ == PathArgument::kindKey ) | |
3357 { | |
3358 if ( !node->isObject() ) | |
3359 { | |
3360 // Error: node is not an object at position... | |
3361 } | |
3362 node = &((*node)[arg.key_]); | |
3363 } | |
3364 } | |
3365 return *node; | |
3366 } | |
3367 | |
3368 | |
3369 } // namespace Json | |
3370 | |
3371 // ////////////////////////////////////////////////////////////////////// | |
3372 // End of content of file: src/lib_json/json_value.cpp | |
3373 // ////////////////////////////////////////////////////////////////////// | |
3374 | |
3375 | |
3376 | |
3377 | |
3378 | |
3379 | |
3380 // ////////////////////////////////////////////////////////////////////// | |
3381 // Beginning of content of file: src/lib_json/json_writer.cpp | |
3382 // ////////////////////////////////////////////////////////////////////// | |
3383 | |
3384 // Copyright 2007-2010 Baptiste Lepilleur | |
3385 // Distributed under MIT license, or public domain if desired and | |
3386 // recognized in your jurisdiction. | |
3387 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | |
3388 | |
3389 #if !defined(JSON_IS_AMALGAMATION) | |
3390 # include <json/writer.h> | |
3391 # include "json_tool.h" | |
3392 #endif // if !defined(JSON_IS_AMALGAMATION) | |
3393 #include <utility> | |
3394 #include <assert.h> | |
3395 #include <stdio.h> | |
3396 #include <string.h> | |
3397 #include <iostream> | |
3398 #include <sstream> | |
3399 #include <iomanip> | |
3400 | |
3401 #if _MSC_VER >= 1400 // VC++ 8.0 | |
3402 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. | |
3403 #endif | |
3404 | |
3405 namespace Json { | |
3406 | |
3407 static bool containsControlCharacter( const char* str ) | |
3408 { | |
3409 while ( *str ) | |
3410 { | |
3411 if ( isControlCharacter( *(str++) ) ) | |
3412 return true; | |
3413 } | |
3414 return false; | |
3415 } | |
3416 | |
3417 | |
3418 std::string valueToString( LargestInt value ) | |
3419 { | |
3420 UIntToStringBuffer buffer; | |
3421 char *current = buffer + sizeof(buffer); | |
3422 bool isNegative = value < 0; | |
3423 if ( isNegative ) | |
3424 value = -value; | |
3425 uintToString( LargestUInt(value), current ); | |
3426 if ( isNegative ) | |
3427 *--current = '-'; | |
3428 assert( current >= buffer ); | |
3429 return current; | |
3430 } | |
3431 | |
3432 | |
3433 std::string valueToString( LargestUInt value ) | |
3434 { | |
3435 UIntToStringBuffer buffer; | |
3436 char *current = buffer + sizeof(buffer); | |
3437 uintToString( value, current ); | |
3438 assert( current >= buffer ); | |
3439 return current; | |
3440 } | |
3441 | |
3442 #if defined(JSON_HAS_INT64) | |
3443 | |
3444 std::string valueToString( Int value ) | |
3445 { | |
3446 return valueToString( LargestInt(value) ); | |
3447 } | |
3448 | |
3449 | |
3450 std::string valueToString( UInt value ) | |
3451 { | |
3452 return valueToString( LargestUInt(value) ); | |
3453 } | |
3454 | |
3455 #endif // # if defined(JSON_HAS_INT64) | |
3456 | |
3457 | |
3458 std::string valueToString( double value ) | |
3459 { | |
3460 char buffer[32]; | |
3461 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. | |
3462 sprintf_s(buffer, sizeof(buffer), "%#.16g", value); | |
3463 #else | |
3464 sprintf(buffer, "%#.16g", value); | |
3465 #endif | |
3466 char* ch = buffer + strlen(buffer) - 1; | |
3467 if (*ch != '0') return buffer; // nothing to truncate, so save time | |
3468 while(ch > buffer && *ch == '0'){ | |
3469 --ch; | |
3470 } | |
3471 char* last_nonzero = ch; | |
3472 while(ch >= buffer){ | |
3473 switch(*ch){ | |
3474 case '0': | |
3475 case '1': | |
3476 case '2': | |
3477 case '3': | |
3478 case '4': | |
3479 case '5': | |
3480 case '6': | |
3481 case '7': | |
3482 case '8': | |
3483 case '9': | |
3484 --ch; | |
3485 continue; | |
3486 case '.': | |
3487 // Truncate zeroes to save bytes in output, but keep one. | |
3488 *(last_nonzero+2) = '\0'; | |
3489 return buffer; | |
3490 default: | |
3491 return buffer; | |
3492 } | |
3493 } | |
3494 return buffer; | |
3495 } | |
3496 | |
3497 | |
3498 std::string valueToString( bool value ) | |
3499 { | |
3500 return value ? "true" : "false"; | |
3501 } | |
3502 | |
3503 std::string valueToQuotedString( const char *value ) | |
3504 { | |
3505 // Not sure how to handle unicode... | |
3506 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) | |
3507 return std::string("\"") + value + "\""; | |
3508 // We have to walk value and escape any special characters. | |
3509 // Appending to std::string is not efficient, but this should be rare. | |
3510 // (Note: forward slashes are *not* rare, but I am not escaping them.) | |
3511 std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL | |
3512 std::string result; | |
3513 result.reserve(maxsize); // to avoid lots of mallocs | |
3514 result += "\""; | |
3515 for (const char* c=value; *c != 0; ++c) | |
3516 { | |
3517 switch(*c) | |
3518 { | |
3519 case '\"': | |
3520 result += "\\\""; | |
3521 break; | |
3522 case '\\': | |
3523 result += "\\\\"; | |
3524 break; | |
3525 case '\b': | |
3526 result += "\\b"; | |
3527 break; | |
3528 case '\f': | |
3529 result += "\\f"; | |
3530 break; | |
3531 case '\n': | |
3532 result += "\\n"; | |
3533 break; | |
3534 case '\r': | |
3535 result += "\\r"; | |
3536 break; | |
3537 case '\t': | |
3538 result += "\\t"; | |
3539 break; | |
3540 //case '/': | |
3541 // Even though \/ is considered a legal escape in JSON, a bare | |
3542 // slash is also legal, so I see no reason to escape it. | |
3543 // (I hope I am not misunderstanding something. | |
3544 // blep notes: actually escaping \/ may be useful in javascript to avoid </ | |
3545 // sequence. | |
3546 // Should add a flag to allow this compatibility mode and prevent this | |
3547 // sequence from occurring. | |
3548 default: | |
3549 if ( isControlCharacter( *c ) ) | |
3550 { | |
3551 std::ostringstream oss; | |
3552 oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); | |
3553 result += oss.str(); | |
3554 } | |
3555 else | |
3556 { | |
3557 result += *c; | |
3558 } | |
3559 break; | |
3560 } | |
3561 } | |
3562 result += "\""; | |
3563 return result; | |
3564 } | |
3565 | |
3566 // Class Writer | |
3567 // ////////////////////////////////////////////////////////////////// | |
3568 Writer::~Writer() | |
3569 { | |
3570 } | |
3571 | |
3572 | |
3573 // Class FastWriter | |
3574 // ////////////////////////////////////////////////////////////////// | |
3575 | |
3576 FastWriter::FastWriter() | |
3577 : yamlCompatiblityEnabled_( false ) | |
3578 { | |
3579 } | |
3580 | |
3581 | |
3582 void | |
3583 FastWriter::enableYAMLCompatibility() | |
3584 { | |
3585 yamlCompatiblityEnabled_ = true; | |
3586 } | |
3587 | |
3588 | |
3589 std::string | |
3590 FastWriter::write( const Value &root ) | |
3591 { | |
3592 document_ = ""; | |
3593 writeValue( root ); | |
3594 document_ += "\n"; | |
3595 return document_; | |
3596 } | |
3597 | |
3598 | |
3599 void | |
3600 FastWriter::writeValue( const Value &value ) | |
3601 { | |
3602 switch ( value.type() ) | |
3603 { | |
3604 case nullValue: | |
3605 document_ += "null"; | |
3606 break; | |
3607 case intValue: | |
3608 document_ += valueToString( value.asLargestInt() ); | |
3609 break; | |
3610 case uintValue: | |
3611 document_ += valueToString( value.asLargestUInt() ); | |
3612 break; | |
3613 case realValue: | |
3614 document_ += valueToString( value.asDouble() ); | |
3615 break; | |
3616 case stringValue: | |
3617 document_ += valueToQuotedString( value.asCString() ); | |
3618 break; | |
3619 case booleanValue: | |
3620 document_ += valueToString( value.asBool() ); | |
3621 break; | |
3622 case arrayValue: | |
3623 { | |
3624 document_ += "["; | |
3625 int size = value.size(); | |
3626 for ( int index =0; index < size; ++index ) | |
3627 { | |
3628 if ( index > 0 ) | |
3629 document_ += ","; | |
3630 writeValue( value[index] ); | |
3631 } | |
3632 document_ += "]"; | |
3633 } | |
3634 break; | |
3635 case objectValue: | |
3636 { | |
3637 Value::Members members( value.getMemberNames() ); | |
3638 document_ += "{"; | |
3639 for ( Value::Members::iterator it = members.begin(); | |
3640 it != members.end(); | |
3641 ++it ) | |
3642 { | |
3643 const std::string &name = *it; | |
3644 if ( it != members.begin() ) | |
3645 document_ += ","; | |
3646 document_ += valueToQuotedString( name.c_str() ); | |
3647 document_ += yamlCompatiblityEnabled_ ? ": " | |
3648 : ":"; | |
3649 writeValue( value[name] ); | |
3650 } | |
3651 document_ += "}"; | |
3652 } | |
3653 break; | |
3654 } | |
3655 } | |
3656 | |
3657 | |
3658 // Class StyledWriter | |
3659 // ////////////////////////////////////////////////////////////////// | |
3660 | |
3661 StyledWriter::StyledWriter() | |
3662 : rightMargin_( 74 ) | |
3663 , indentSize_( 3 ) | |
3664 { | |
3665 } | |
3666 | |
3667 | |
3668 std::string | |
3669 StyledWriter::write( const Value &root ) | |
3670 { | |
3671 document_ = ""; | |
3672 addChildValues_ = false; | |
3673 indentString_ = ""; | |
3674 writeCommentBeforeValue( root ); | |
3675 writeValue( root ); | |
3676 writeCommentAfterValueOnSameLine( root ); | |
3677 document_ += "\n"; | |
3678 return document_; | |
3679 } | |
3680 | |
3681 | |
3682 void | |
3683 StyledWriter::writeValue( const Value &value ) | |
3684 { | |
3685 switch ( value.type() ) | |
3686 { | |
3687 case nullValue: | |
3688 pushValue( "null" ); | |
3689 break; | |
3690 case intValue: | |
3691 pushValue( valueToString( value.asLargestInt() ) ); | |
3692 break; | |
3693 case uintValue: | |
3694 pushValue( valueToString( value.asLargestUInt() ) ); | |
3695 break; | |
3696 case realValue: | |
3697 pushValue( valueToString( value.asDouble() ) ); | |
3698 break; | |
3699 case stringValue: | |
3700 pushValue( valueToQuotedString( value.asCString() ) ); | |
3701 break; | |
3702 case booleanValue: | |
3703 pushValue( valueToString( value.asBool() ) ); | |
3704 break; | |
3705 case arrayValue: | |
3706 writeArrayValue( value); | |
3707 break; | |
3708 case objectValue: | |
3709 { | |
3710 Value::Members members( value.getMemberNames() ); | |
3711 if ( members.empty() ) | |
3712 pushValue( "{}" ); | |
3713 else | |
3714 { | |
3715 writeWithIndent( "{" ); | |
3716 indent(); | |
3717 Value::Members::iterator it = members.begin(); | |
3718 for (;;) | |
3719 { | |
3720 const std::string &name = *it; | |
3721 const Value &childValue = value[name]; | |
3722 writeCommentBeforeValue( childValue ); | |
3723 writeWithIndent( valueToQuotedString( name.c_str() ) ); | |
3724 document_ += " : "; | |
3725 writeValue( childValue ); | |
3726 if ( ++it == members.end() ) | |
3727 { | |
3728 writeCommentAfterValueOnSameLine( childValue ); | |
3729 break; | |
3730 } | |
3731 document_ += ","; | |
3732 writeCommentAfterValueOnSameLine( childValue ); | |
3733 } | |
3734 unindent(); | |
3735 writeWithIndent( "}" ); | |
3736 } | |
3737 } | |
3738 break; | |
3739 } | |
3740 } | |
3741 | |
3742 | |
3743 void | |
3744 StyledWriter::writeArrayValue( const Value &value ) | |
3745 { | |
3746 unsigned size = value.size(); | |
3747 if ( size == 0 ) | |
3748 pushValue( "[]" ); | |
3749 else | |
3750 { | |
3751 bool isArrayMultiLine = isMultineArray( value ); | |
3752 if ( isArrayMultiLine ) | |
3753 { | |
3754 writeWithIndent( "[" ); | |
3755 indent(); | |
3756 bool hasChildValue = !childValues_.empty(); | |
3757 unsigned index =0; | |
3758 for (;;) | |
3759 { | |
3760 const Value &childValue = value[index]; | |
3761 writeCommentBeforeValue( childValue ); | |
3762 if ( hasChildValue ) | |
3763 writeWithIndent( childValues_[index] ); | |
3764 else | |
3765 { | |
3766 writeIndent(); | |
3767 writeValue( childValue ); | |
3768 } | |
3769 if ( ++index == size ) | |
3770 { | |
3771 writeCommentAfterValueOnSameLine( childValue ); | |
3772 break; | |
3773 } | |
3774 document_ += ","; | |
3775 writeCommentAfterValueOnSameLine( childValue ); | |
3776 } | |
3777 unindent(); | |
3778 writeWithIndent( "]" ); | |
3779 } | |
3780 else // output on a single line | |
3781 { | |
3782 assert( childValues_.size() == size ); | |
3783 document_ += "[ "; | |
3784 for ( unsigned index =0; index < size; ++index ) | |
3785 { | |
3786 if ( index > 0 ) | |
3787 document_ += ", "; | |
3788 document_ += childValues_[index]; | |
3789 } | |
3790 document_ += " ]"; | |
3791 } | |
3792 } | |
3793 } | |
3794 | |
3795 | |
3796 bool | |
3797 StyledWriter::isMultineArray( const Value &value ) | |
3798 { | |
3799 int size = value.size(); | |
3800 bool isMultiLine = size*3 >= rightMargin_ ; | |
3801 childValues_.clear(); | |
3802 for ( int index =0; index < size && !isMultiLine; ++index ) | |
3803 { | |
3804 const Value &childValue = value[index]; | |
3805 isMultiLine = isMultiLine || | |
3806 ( (childValue.isArray() || childValue.isObject()) && | |
3807 childValue.size() > 0 ); | |
3808 } | |
3809 if ( !isMultiLine ) // check if line length > max line length | |
3810 { | |
3811 childValues_.reserve( size ); | |
3812 addChildValues_ = true; | |
3813 int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' | |
3814 for ( int index =0; index < size && !isMultiLine; ++index ) | |
3815 { | |
3816 writeValue( value[index] ); | |
3817 lineLength += int( childValues_[index].length() ); | |
3818 isMultiLine = isMultiLine && hasCommentForValue( value[index] ); | |
3819 } | |
3820 addChildValues_ = false; | |
3821 isMultiLine = isMultiLine || lineLength >= rightMargin_; | |
3822 } | |
3823 return isMultiLine; | |
3824 } | |
3825 | |
3826 | |
3827 void | |
3828 StyledWriter::pushValue( const std::string &value ) | |
3829 { | |
3830 if ( addChildValues_ ) | |
3831 childValues_.push_back( value ); | |
3832 else | |
3833 document_ += value; | |
3834 } | |
3835 | |
3836 | |
3837 void | |
3838 StyledWriter::writeIndent() | |
3839 { | |
3840 if ( !document_.empty() ) | |
3841 { | |
3842 char last = document_[document_.length()-1]; | |
3843 if ( last == ' ' ) // already indented | |
3844 return; | |
3845 if ( last != '\n' ) // Comments may add new-line | |
3846 document_ += '\n'; | |
3847 } | |
3848 document_ += indentString_; | |
3849 } | |
3850 | |
3851 | |
3852 void | |
3853 StyledWriter::writeWithIndent( const std::string &value ) | |
3854 { | |
3855 writeIndent(); | |
3856 document_ += value; | |
3857 } | |
3858 | |
3859 | |
3860 void | |
3861 StyledWriter::indent() | |
3862 { | |
3863 indentString_ += std::string( indentSize_, ' ' ); | |
3864 } | |
3865 | |
3866 | |
3867 void | |
3868 StyledWriter::unindent() | |
3869 { | |
3870 assert( int(indentString_.size()) >= indentSize_ ); | |
3871 indentString_.resize( indentString_.size() - indentSize_ ); | |
3872 } | |
3873 | |
3874 | |
3875 void | |
3876 StyledWriter::writeCommentBeforeValue( const Value &root ) | |
3877 { | |
3878 if ( !root.hasComment( commentBefore ) ) | |
3879 return; | |
3880 document_ += normalizeEOL( root.getComment( commentBefore ) ); | |
3881 document_ += "\n"; | |
3882 } | |
3883 | |
3884 | |
3885 void | |
3886 StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) | |
3887 { | |
3888 if ( root.hasComment( commentAfterOnSameLine ) ) | |
3889 document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); | |
3890 | |
3891 if ( root.hasComment( commentAfter ) ) | |
3892 { | |
3893 document_ += "\n"; | |
3894 document_ += normalizeEOL( root.getComment( commentAfter ) ); | |
3895 document_ += "\n"; | |
3896 } | |
3897 } | |
3898 | |
3899 | |
3900 bool | |
3901 StyledWriter::hasCommentForValue( const Value &value ) | |
3902 { | |
3903 return value.hasComment( commentBefore ) | |
3904 || value.hasComment( commentAfterOnSameLine ) | |
3905 || value.hasComment( commentAfter ); | |
3906 } | |
3907 | |
3908 | |
3909 std::string | |
3910 StyledWriter::normalizeEOL( const std::string &text ) | |
3911 { | |
3912 std::string normalized; | |
3913 normalized.reserve( text.length() ); | |
3914 const char *begin = text.c_str(); | |
3915 const char *end = begin + text.length(); | |
3916 const char *current = begin; | |
3917 while ( current != end ) | |
3918 { | |
3919 char c = *current++; | |
3920 if ( c == '\r' ) // mac or dos EOL | |
3921 { | |
3922 if ( *current == '\n' ) // convert dos EOL | |
3923 ++current; | |
3924 normalized += '\n'; | |
3925 } | |
3926 else // handle unix EOL & other char | |
3927 normalized += c; | |
3928 } | |
3929 return normalized; | |
3930 } | |
3931 | |
3932 | |
3933 // Class StyledStreamWriter | |
3934 // ////////////////////////////////////////////////////////////////// | |
3935 | |
3936 StyledStreamWriter::StyledStreamWriter( std::string indentation ) | |
3937 : document_(NULL) | |
3938 , rightMargin_( 74 ) | |
3939 , indentation_( indentation ) | |
3940 { | |
3941 } | |
3942 | |
3943 | |
3944 void | |
3945 StyledStreamWriter::write( std::ostream &out, const Value &root ) | |
3946 { | |
3947 document_ = &out; | |
3948 addChildValues_ = false; | |
3949 indentString_ = ""; | |
3950 writeCommentBeforeValue( root ); | |
3951 writeValue( root ); | |
3952 writeCommentAfterValueOnSameLine( root ); | |
3953 *document_ << "\n"; | |
3954 document_ = NULL; // Forget the stream, for safety. | |
3955 } | |
3956 | |
3957 | |
3958 void | |
3959 StyledStreamWriter::writeValue( const Value &value ) | |
3960 { | |
3961 switch ( value.type() ) | |
3962 { | |
3963 case nullValue: | |
3964 pushValue( "null" ); | |
3965 break; | |
3966 case intValue: | |
3967 pushValue( valueToString( value.asLargestInt() ) ); | |
3968 break; | |
3969 case uintValue: | |
3970 pushValue( valueToString( value.asLargestUInt() ) ); | |
3971 break; | |
3972 case realValue: | |
3973 pushValue( valueToString( value.asDouble() ) ); | |
3974 break; | |
3975 case stringValue: | |
3976 pushValue( valueToQuotedString( value.asCString() ) ); | |
3977 break; | |
3978 case booleanValue: | |
3979 pushValue( valueToString( value.asBool() ) ); | |
3980 break; | |
3981 case arrayValue: | |
3982 writeArrayValue( value); | |
3983 break; | |
3984 case objectValue: | |
3985 { | |
3986 Value::Members members( value.getMemberNames() ); | |
3987 if ( members.empty() ) | |
3988 pushValue( "{}" ); | |
3989 else | |
3990 { | |
3991 writeWithIndent( "{" ); | |
3992 indent(); | |
3993 Value::Members::iterator it = members.begin(); | |
3994 for (;;) | |
3995 { | |
3996 const std::string &name = *it; | |
3997 const Value &childValue = value[name]; | |
3998 writeCommentBeforeValue( childValue ); | |
3999 writeWithIndent( valueToQuotedString( name.c_str() ) ); | |
4000 *document_ << " : "; | |
4001 writeValue( childValue ); | |
4002 if ( ++it == members.end() ) | |
4003 { | |
4004 writeCommentAfterValueOnSameLine( childValue ); | |
4005 break; | |
4006 } | |
4007 *document_ << ","; | |
4008 writeCommentAfterValueOnSameLine( childValue ); | |
4009 } | |
4010 unindent(); | |
4011 writeWithIndent( "}" ); | |
4012 } | |
4013 } | |
4014 break; | |
4015 } | |
4016 } | |
4017 | |
4018 | |
4019 void | |
4020 StyledStreamWriter::writeArrayValue( const Value &value ) | |
4021 { | |
4022 unsigned size = value.size(); | |
4023 if ( size == 0 ) | |
4024 pushValue( "[]" ); | |
4025 else | |
4026 { | |
4027 bool isArrayMultiLine = isMultineArray( value ); | |
4028 if ( isArrayMultiLine ) | |
4029 { | |
4030 writeWithIndent( "[" ); | |
4031 indent(); | |
4032 bool hasChildValue = !childValues_.empty(); | |
4033 unsigned index =0; | |
4034 for (;;) | |
4035 { | |
4036 const Value &childValue = value[index]; | |
4037 writeCommentBeforeValue( childValue ); | |
4038 if ( hasChildValue ) | |
4039 writeWithIndent( childValues_[index] ); | |
4040 else | |
4041 { | |
4042 writeIndent(); | |
4043 writeValue( childValue ); | |
4044 } | |
4045 if ( ++index == size ) | |
4046 { | |
4047 writeCommentAfterValueOnSameLine( childValue ); | |
4048 break; | |
4049 } | |
4050 *document_ << ","; | |
4051 writeCommentAfterValueOnSameLine( childValue ); | |
4052 } | |
4053 unindent(); | |
4054 writeWithIndent( "]" ); | |
4055 } | |
4056 else // output on a single line | |
4057 { | |
4058 assert( childValues_.size() == size ); | |
4059 *document_ << "[ "; | |
4060 for ( unsigned index =0; index < size; ++index ) | |
4061 { | |
4062 if ( index > 0 ) | |
4063 *document_ << ", "; | |
4064 *document_ << childValues_[index]; | |
4065 } | |
4066 *document_ << " ]"; | |
4067 } | |
4068 } | |
4069 } | |
4070 | |
4071 | |
4072 bool | |
4073 StyledStreamWriter::isMultineArray( const Value &value ) | |
4074 { | |
4075 int size = value.size(); | |
4076 bool isMultiLine = size*3 >= rightMargin_ ; | |
4077 childValues_.clear(); | |
4078 for ( int index =0; index < size && !isMultiLine; ++index ) | |
4079 { | |
4080 const Value &childValue = value[index]; | |
4081 isMultiLine = isMultiLine || | |
4082 ( (childValue.isArray() || childValue.isObject()) && | |
4083 childValue.size() > 0 ); | |
4084 } | |
4085 if ( !isMultiLine ) // check if line length > max line length | |
4086 { | |
4087 childValues_.reserve( size ); | |
4088 addChildValues_ = true; | |
4089 int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' | |
4090 for ( int index =0; index < size && !isMultiLine; ++index ) | |
4091 { | |
4092 writeValue( value[index] ); | |
4093 lineLength += int( childValues_[index].length() ); | |
4094 isMultiLine = isMultiLine && hasCommentForValue( value[index] ); | |
4095 } | |
4096 addChildValues_ = false; | |
4097 isMultiLine = isMultiLine || lineLength >= rightMargin_; | |
4098 } | |
4099 return isMultiLine; | |
4100 } | |
4101 | |
4102 | |
4103 void | |
4104 StyledStreamWriter::pushValue( const std::string &value ) | |
4105 { | |
4106 if ( addChildValues_ ) | |
4107 childValues_.push_back( value ); | |
4108 else | |
4109 *document_ << value; | |
4110 } | |
4111 | |
4112 | |
4113 void | |
4114 StyledStreamWriter::writeIndent() | |
4115 { | |
4116 /* | |
4117 Some comments in this method would have been nice. ;-) | |
4118 | |
4119 if ( !document_.empty() ) | |
4120 { | |
4121 char last = document_[document_.length()-1]; | |
4122 if ( last == ' ' ) // already indented | |
4123 return; | |
4124 if ( last != '\n' ) // Comments may add new-line | |
4125 *document_ << '\n'; | |
4126 } | |
4127 */ | |
4128 *document_ << '\n' << indentString_; | |
4129 } | |
4130 | |
4131 | |
4132 void | |
4133 StyledStreamWriter::writeWithIndent( const std::string &value ) | |
4134 { | |
4135 writeIndent(); | |
4136 *document_ << value; | |
4137 } | |
4138 | |
4139 | |
4140 void | |
4141 StyledStreamWriter::indent() | |
4142 { | |
4143 indentString_ += indentation_; | |
4144 } | |
4145 | |
4146 | |
4147 void | |
4148 StyledStreamWriter::unindent() | |
4149 { | |
4150 assert( indentString_.size() >= indentation_.size() ); | |
4151 indentString_.resize( indentString_.size() - indentation_.size() ); | |
4152 } | |
4153 | |
4154 | |
4155 void | |
4156 StyledStreamWriter::writeCommentBeforeValue( const Value &root ) | |
4157 { | |
4158 if ( !root.hasComment( commentBefore ) ) | |
4159 return; | |
4160 *document_ << normalizeEOL( root.getComment( commentBefore ) ); | |
4161 *document_ << "\n"; | |
4162 } | |
4163 | |
4164 | |
4165 void | |
4166 StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) | |
4167 { | |
4168 if ( root.hasComment( commentAfterOnSameLine ) ) | |
4169 *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); | |
4170 | |
4171 if ( root.hasComment( commentAfter ) ) | |
4172 { | |
4173 *document_ << "\n"; | |
4174 *document_ << normalizeEOL( root.getComment( commentAfter ) ); | |
4175 *document_ << "\n"; | |
4176 } | |
4177 } | |
4178 | |
4179 | |
4180 bool | |
4181 StyledStreamWriter::hasCommentForValue( const Value &value ) | |
4182 { | |
4183 return value.hasComment( commentBefore ) | |
4184 || value.hasComment( commentAfterOnSameLine ) | |
4185 || value.hasComment( commentAfter ); | |
4186 } | |
4187 | |
4188 | |
4189 std::string | |
4190 StyledStreamWriter::normalizeEOL( const std::string &text ) | |
4191 { | |
4192 std::string normalized; | |
4193 normalized.reserve( text.length() ); | |
4194 const char *begin = text.c_str(); | |
4195 const char *end = begin + text.length(); | |
4196 const char *current = begin; | |
4197 while ( current != end ) | |
4198 { | |
4199 char c = *current++; | |
4200 if ( c == '\r' ) // mac or dos EOL | |
4201 { | |
4202 if ( *current == '\n' ) // convert dos EOL | |
4203 ++current; | |
4204 normalized += '\n'; | |
4205 } | |
4206 else // handle unix EOL & other char | |
4207 normalized += c; | |
4208 } | |
4209 return normalized; | |
4210 } | |
4211 | |
4212 | |
4213 std::ostream& operator<<( std::ostream &sout, const Value &root ) | |
4214 { | |
4215 Json::StyledStreamWriter writer; | |
4216 writer.write(sout, root); | |
4217 return sout; | |
4218 } | |
4219 | |
4220 | |
4221 } // namespace Json | |
4222 | |
4223 // ////////////////////////////////////////////////////////////////////// | |
4224 // End of content of file: src/lib_json/json_writer.cpp | |
4225 // ////////////////////////////////////////////////////////////////////// | |
4226 | |
4227 | |
4228 | |
4229 | |
4230 |