json test

Committer:
tgw
Date:
Fri Jan 26 06:05:31 2018 +0000
Revision:
0:2ee762ea11b3
json

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tgw 0:2ee762ea11b3 1 // Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
tgw 0:2ee762ea11b3 2 // Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
tgw 0:2ee762ea11b3 3 // Distributed under MIT license, or public domain if desired and
tgw 0:2ee762ea11b3 4 // recognized in your jurisdiction.
tgw 0:2ee762ea11b3 5 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
tgw 0:2ee762ea11b3 6
tgw 0:2ee762ea11b3 7 #if !defined(JSON_IS_AMALGAMATION)
tgw 0:2ee762ea11b3 8 #include <json/assertions.h>
tgw 0:2ee762ea11b3 9 #include <json/reader.h>
tgw 0:2ee762ea11b3 10 #include <json/value.h>
tgw 0:2ee762ea11b3 11 #include "json_tool.h"
tgw 0:2ee762ea11b3 12 #endif // if !defined(JSON_IS_AMALGAMATION)
tgw 0:2ee762ea11b3 13 #include <utility>
tgw 0:2ee762ea11b3 14 #include <cstdio>
tgw 0:2ee762ea11b3 15 #include <cassert>
tgw 0:2ee762ea11b3 16 #include <cstring>
tgw 0:2ee762ea11b3 17 #include <istream>
tgw 0:2ee762ea11b3 18 #include <sstream>
tgw 0:2ee762ea11b3 19 #include <memory>
tgw 0:2ee762ea11b3 20 #include <set>
tgw 0:2ee762ea11b3 21 #include <limits>
tgw 0:2ee762ea11b3 22
tgw 0:2ee762ea11b3 23 #if defined(_MSC_VER)
tgw 0:2ee762ea11b3 24 #if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above
tgw 0:2ee762ea11b3 25 #define snprintf sprintf_s
tgw 0:2ee762ea11b3 26 #elif _MSC_VER >= 1900 // VC++ 14.0 and above
tgw 0:2ee762ea11b3 27 #define snprintf std::snprintf
tgw 0:2ee762ea11b3 28 #else
tgw 0:2ee762ea11b3 29 #define snprintf _snprintf
tgw 0:2ee762ea11b3 30 #endif
tgw 0:2ee762ea11b3 31 #elif defined(__ANDROID__) || defined(__QNXNTO__)
tgw 0:2ee762ea11b3 32 #define snprintf snprintf
tgw 0:2ee762ea11b3 33 #elif __cplusplus >= 201103L
tgw 0:2ee762ea11b3 34 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
tgw 0:2ee762ea11b3 35 #define snprintf std::snprintf
tgw 0:2ee762ea11b3 36 #endif
tgw 0:2ee762ea11b3 37 #endif
tgw 0:2ee762ea11b3 38
tgw 0:2ee762ea11b3 39 #if defined(__QNXNTO__)
tgw 0:2ee762ea11b3 40 #define sscanf std::sscanf
tgw 0:2ee762ea11b3 41 #endif
tgw 0:2ee762ea11b3 42
tgw 0:2ee762ea11b3 43 #if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
tgw 0:2ee762ea11b3 44 // Disable warning about strdup being deprecated.
tgw 0:2ee762ea11b3 45 #pragma warning(disable : 4996)
tgw 0:2ee762ea11b3 46 #endif
tgw 0:2ee762ea11b3 47
tgw 0:2ee762ea11b3 48 // Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit
tgw 0:2ee762ea11b3 49 #if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
tgw 0:2ee762ea11b3 50 #define JSONCPP_DEPRECATED_STACK_LIMIT 1000
tgw 0:2ee762ea11b3 51 #endif
tgw 0:2ee762ea11b3 52
tgw 0:2ee762ea11b3 53 using namespace std;
tgw 0:2ee762ea11b3 54
tgw 0:2ee762ea11b3 55 static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
tgw 0:2ee762ea11b3 56
tgw 0:2ee762ea11b3 57 namespace Json {
tgw 0:2ee762ea11b3 58
tgw 0:2ee762ea11b3 59 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
tgw 0:2ee762ea11b3 60 typedef std::unique_ptr<CharReader> CharReaderPtr;
tgw 0:2ee762ea11b3 61 #else
tgw 0:2ee762ea11b3 62 typedef std::auto_ptr<CharReader> CharReaderPtr;
tgw 0:2ee762ea11b3 63 #endif
tgw 0:2ee762ea11b3 64
tgw 0:2ee762ea11b3 65 // Implementation of class Features
tgw 0:2ee762ea11b3 66 // ////////////////////////////////
tgw 0:2ee762ea11b3 67
tgw 0:2ee762ea11b3 68 Features::Features()
tgw 0:2ee762ea11b3 69 : allowComments_(true), strictRoot_(false),
tgw 0:2ee762ea11b3 70 allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
tgw 0:2ee762ea11b3 71
tgw 0:2ee762ea11b3 72 Features Features::all() { return Features(); }
tgw 0:2ee762ea11b3 73
tgw 0:2ee762ea11b3 74 Features Features::strictMode() {
tgw 0:2ee762ea11b3 75 Features features;
tgw 0:2ee762ea11b3 76 features.allowComments_ = false;
tgw 0:2ee762ea11b3 77 features.strictRoot_ = true;
tgw 0:2ee762ea11b3 78 features.allowDroppedNullPlaceholders_ = false;
tgw 0:2ee762ea11b3 79 features.allowNumericKeys_ = false;
tgw 0:2ee762ea11b3 80 return features;
tgw 0:2ee762ea11b3 81 }
tgw 0:2ee762ea11b3 82
tgw 0:2ee762ea11b3 83 // Implementation of class Reader
tgw 0:2ee762ea11b3 84 // ////////////////////////////////
tgw 0:2ee762ea11b3 85
tgw 0:2ee762ea11b3 86 bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
tgw 0:2ee762ea11b3 87 for (; begin < end; ++begin)
tgw 0:2ee762ea11b3 88 if (*begin == '\n' || *begin == '\r')
tgw 0:2ee762ea11b3 89 return true;
tgw 0:2ee762ea11b3 90 return false;
tgw 0:2ee762ea11b3 91 }
tgw 0:2ee762ea11b3 92
tgw 0:2ee762ea11b3 93 // Class Reader
tgw 0:2ee762ea11b3 94 // //////////////////////////////////////////////////////////////////
tgw 0:2ee762ea11b3 95
tgw 0:2ee762ea11b3 96 Reader::Reader()
tgw 0:2ee762ea11b3 97 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
tgw 0:2ee762ea11b3 98 lastValue_(), commentsBefore_(), features_(Features::all()),
tgw 0:2ee762ea11b3 99 collectComments_() {}
tgw 0:2ee762ea11b3 100
tgw 0:2ee762ea11b3 101 Reader::Reader(const Features& features)
tgw 0:2ee762ea11b3 102 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
tgw 0:2ee762ea11b3 103 lastValue_(), commentsBefore_(), features_(features), collectComments_() {
tgw 0:2ee762ea11b3 104 }
tgw 0:2ee762ea11b3 105
tgw 0:2ee762ea11b3 106 bool
tgw 0:2ee762ea11b3 107 Reader::parse(const std::string& document, Value& root, bool collectComments) {
tgw 0:2ee762ea11b3 108 document_.assign(document.begin(), document.end());
tgw 0:2ee762ea11b3 109 const char* begin = document_.c_str();
tgw 0:2ee762ea11b3 110 const char* end = begin + document_.length();
tgw 0:2ee762ea11b3 111 return parse(begin, end, root, collectComments);
tgw 0:2ee762ea11b3 112 }
tgw 0:2ee762ea11b3 113
tgw 0:2ee762ea11b3 114 bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
tgw 0:2ee762ea11b3 115 // std::istream_iterator<char> begin(sin);
tgw 0:2ee762ea11b3 116 // std::istream_iterator<char> end;
tgw 0:2ee762ea11b3 117 // Those would allow streamed input from a file, if parse() were a
tgw 0:2ee762ea11b3 118 // template function.
tgw 0:2ee762ea11b3 119
tgw 0:2ee762ea11b3 120 // Since JSONCPP_STRING is reference-counted, this at least does not
tgw 0:2ee762ea11b3 121 // create an extra copy.
tgw 0:2ee762ea11b3 122 JSONCPP_STRING doc;
tgw 0:2ee762ea11b3 123 std::getline(sin, doc, (char)EOF);
tgw 0:2ee762ea11b3 124 return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
tgw 0:2ee762ea11b3 125 }
tgw 0:2ee762ea11b3 126
tgw 0:2ee762ea11b3 127 bool Reader::parse(const char* beginDoc,
tgw 0:2ee762ea11b3 128 const char* endDoc,
tgw 0:2ee762ea11b3 129 Value& root,
tgw 0:2ee762ea11b3 130 bool collectComments) {
tgw 0:2ee762ea11b3 131 if (!features_.allowComments_) {
tgw 0:2ee762ea11b3 132 collectComments = false;
tgw 0:2ee762ea11b3 133 }
tgw 0:2ee762ea11b3 134
tgw 0:2ee762ea11b3 135 begin_ = beginDoc;
tgw 0:2ee762ea11b3 136 end_ = endDoc;
tgw 0:2ee762ea11b3 137 collectComments_ = collectComments;
tgw 0:2ee762ea11b3 138 current_ = begin_;
tgw 0:2ee762ea11b3 139 lastValueEnd_ = 0;
tgw 0:2ee762ea11b3 140 lastValue_ = 0;
tgw 0:2ee762ea11b3 141 commentsBefore_.clear();
tgw 0:2ee762ea11b3 142 errors_.clear();
tgw 0:2ee762ea11b3 143 while (!nodes_.empty())
tgw 0:2ee762ea11b3 144 nodes_.pop();
tgw 0:2ee762ea11b3 145 nodes_.push(&root);
tgw 0:2ee762ea11b3 146
tgw 0:2ee762ea11b3 147 bool successful = readValue();
tgw 0:2ee762ea11b3 148 Token token;
tgw 0:2ee762ea11b3 149 skipCommentTokens(token);
tgw 0:2ee762ea11b3 150 if (collectComments_ && !commentsBefore_.empty())
tgw 0:2ee762ea11b3 151 root.setComment(commentsBefore_, commentAfter);
tgw 0:2ee762ea11b3 152 if (features_.strictRoot_) {
tgw 0:2ee762ea11b3 153 if (!root.isArray() && !root.isObject()) {
tgw 0:2ee762ea11b3 154 // Set error location to start of doc, ideally should be first token found
tgw 0:2ee762ea11b3 155 // in doc
tgw 0:2ee762ea11b3 156 token.type_ = tokenError;
tgw 0:2ee762ea11b3 157 token.start_ = beginDoc;
tgw 0:2ee762ea11b3 158 token.end_ = endDoc;
tgw 0:2ee762ea11b3 159 addError(
tgw 0:2ee762ea11b3 160 "A valid JSON document must be either an array or an object value.",
tgw 0:2ee762ea11b3 161 token);
tgw 0:2ee762ea11b3 162 return false;
tgw 0:2ee762ea11b3 163 }
tgw 0:2ee762ea11b3 164 }
tgw 0:2ee762ea11b3 165 return successful;
tgw 0:2ee762ea11b3 166 }
tgw 0:2ee762ea11b3 167
tgw 0:2ee762ea11b3 168 bool Reader::readValue() {
tgw 0:2ee762ea11b3 169 // readValue() may call itself only if it calls readObject() or ReadArray().
tgw 0:2ee762ea11b3 170 // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue().
tgw 0:2ee762ea11b3 171 // parse() executes one nodes_.push(), so > instead of >=.
tgw 0:2ee762ea11b3 172 if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue().");
tgw 0:2ee762ea11b3 173
tgw 0:2ee762ea11b3 174 Token token;
tgw 0:2ee762ea11b3 175 skipCommentTokens(token);
tgw 0:2ee762ea11b3 176 bool successful = true;
tgw 0:2ee762ea11b3 177
tgw 0:2ee762ea11b3 178 if (collectComments_ && !commentsBefore_.empty()) {
tgw 0:2ee762ea11b3 179 currentValue().setComment(commentsBefore_, commentBefore);
tgw 0:2ee762ea11b3 180 commentsBefore_.clear();
tgw 0:2ee762ea11b3 181 }
tgw 0:2ee762ea11b3 182
tgw 0:2ee762ea11b3 183 switch (token.type_) {
tgw 0:2ee762ea11b3 184 case tokenObjectBegin:
tgw 0:2ee762ea11b3 185 successful = readObject(token);
tgw 0:2ee762ea11b3 186 currentValue().setOffsetLimit(current_ - begin_);
tgw 0:2ee762ea11b3 187 break;
tgw 0:2ee762ea11b3 188 case tokenArrayBegin:
tgw 0:2ee762ea11b3 189 successful = readArray(token);
tgw 0:2ee762ea11b3 190 currentValue().setOffsetLimit(current_ - begin_);
tgw 0:2ee762ea11b3 191 break;
tgw 0:2ee762ea11b3 192 case tokenNumber:
tgw 0:2ee762ea11b3 193 successful = decodeNumber(token);
tgw 0:2ee762ea11b3 194 break;
tgw 0:2ee762ea11b3 195 case tokenString:
tgw 0:2ee762ea11b3 196 successful = decodeString(token);
tgw 0:2ee762ea11b3 197 break;
tgw 0:2ee762ea11b3 198 case tokenTrue:
tgw 0:2ee762ea11b3 199 {
tgw 0:2ee762ea11b3 200 Value v(true);
tgw 0:2ee762ea11b3 201 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 202 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 203 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 204 }
tgw 0:2ee762ea11b3 205 break;
tgw 0:2ee762ea11b3 206 case tokenFalse:
tgw 0:2ee762ea11b3 207 {
tgw 0:2ee762ea11b3 208 Value v(false);
tgw 0:2ee762ea11b3 209 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 210 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 211 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 212 }
tgw 0:2ee762ea11b3 213 break;
tgw 0:2ee762ea11b3 214 case tokenNull:
tgw 0:2ee762ea11b3 215 {
tgw 0:2ee762ea11b3 216 Value v;
tgw 0:2ee762ea11b3 217 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 218 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 219 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 220 }
tgw 0:2ee762ea11b3 221 break;
tgw 0:2ee762ea11b3 222 case tokenArraySeparator:
tgw 0:2ee762ea11b3 223 case tokenObjectEnd:
tgw 0:2ee762ea11b3 224 case tokenArrayEnd:
tgw 0:2ee762ea11b3 225 if (features_.allowDroppedNullPlaceholders_) {
tgw 0:2ee762ea11b3 226 // "Un-read" the current token and mark the current value as a null
tgw 0:2ee762ea11b3 227 // token.
tgw 0:2ee762ea11b3 228 current_--;
tgw 0:2ee762ea11b3 229 Value v;
tgw 0:2ee762ea11b3 230 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 231 currentValue().setOffsetStart(current_ - begin_ - 1);
tgw 0:2ee762ea11b3 232 currentValue().setOffsetLimit(current_ - begin_);
tgw 0:2ee762ea11b3 233 break;
tgw 0:2ee762ea11b3 234 } // Else, fall through...
tgw 0:2ee762ea11b3 235 default:
tgw 0:2ee762ea11b3 236 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 237 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 238 return addError("Syntax error: value, object or array expected.", token);
tgw 0:2ee762ea11b3 239 }
tgw 0:2ee762ea11b3 240
tgw 0:2ee762ea11b3 241 if (collectComments_) {
tgw 0:2ee762ea11b3 242 lastValueEnd_ = current_;
tgw 0:2ee762ea11b3 243 lastValue_ = &currentValue();
tgw 0:2ee762ea11b3 244 }
tgw 0:2ee762ea11b3 245
tgw 0:2ee762ea11b3 246 return successful;
tgw 0:2ee762ea11b3 247 }
tgw 0:2ee762ea11b3 248
tgw 0:2ee762ea11b3 249 void Reader::skipCommentTokens(Token& token) {
tgw 0:2ee762ea11b3 250 if (features_.allowComments_) {
tgw 0:2ee762ea11b3 251 do {
tgw 0:2ee762ea11b3 252 readToken(token);
tgw 0:2ee762ea11b3 253 } while (token.type_ == tokenComment);
tgw 0:2ee762ea11b3 254 } else {
tgw 0:2ee762ea11b3 255 readToken(token);
tgw 0:2ee762ea11b3 256 }
tgw 0:2ee762ea11b3 257 }
tgw 0:2ee762ea11b3 258
tgw 0:2ee762ea11b3 259 bool Reader::readToken(Token& token) {
tgw 0:2ee762ea11b3 260 skipSpaces();
tgw 0:2ee762ea11b3 261 token.start_ = current_;
tgw 0:2ee762ea11b3 262 Char c = getNextChar();
tgw 0:2ee762ea11b3 263 bool ok = true;
tgw 0:2ee762ea11b3 264 switch (c) {
tgw 0:2ee762ea11b3 265 case '{':
tgw 0:2ee762ea11b3 266 token.type_ = tokenObjectBegin;
tgw 0:2ee762ea11b3 267 break;
tgw 0:2ee762ea11b3 268 case '}':
tgw 0:2ee762ea11b3 269 token.type_ = tokenObjectEnd;
tgw 0:2ee762ea11b3 270 break;
tgw 0:2ee762ea11b3 271 case '[':
tgw 0:2ee762ea11b3 272 token.type_ = tokenArrayBegin;
tgw 0:2ee762ea11b3 273 break;
tgw 0:2ee762ea11b3 274 case ']':
tgw 0:2ee762ea11b3 275 token.type_ = tokenArrayEnd;
tgw 0:2ee762ea11b3 276 break;
tgw 0:2ee762ea11b3 277 case '"':
tgw 0:2ee762ea11b3 278 token.type_ = tokenString;
tgw 0:2ee762ea11b3 279 ok = readString();
tgw 0:2ee762ea11b3 280 break;
tgw 0:2ee762ea11b3 281 case '/':
tgw 0:2ee762ea11b3 282 token.type_ = tokenComment;
tgw 0:2ee762ea11b3 283 ok = readComment();
tgw 0:2ee762ea11b3 284 break;
tgw 0:2ee762ea11b3 285 case '0':
tgw 0:2ee762ea11b3 286 case '1':
tgw 0:2ee762ea11b3 287 case '2':
tgw 0:2ee762ea11b3 288 case '3':
tgw 0:2ee762ea11b3 289 case '4':
tgw 0:2ee762ea11b3 290 case '5':
tgw 0:2ee762ea11b3 291 case '6':
tgw 0:2ee762ea11b3 292 case '7':
tgw 0:2ee762ea11b3 293 case '8':
tgw 0:2ee762ea11b3 294 case '9':
tgw 0:2ee762ea11b3 295 case '-':
tgw 0:2ee762ea11b3 296 token.type_ = tokenNumber;
tgw 0:2ee762ea11b3 297 readNumber();
tgw 0:2ee762ea11b3 298 break;
tgw 0:2ee762ea11b3 299 case 't':
tgw 0:2ee762ea11b3 300 token.type_ = tokenTrue;
tgw 0:2ee762ea11b3 301 ok = match("rue", 3);
tgw 0:2ee762ea11b3 302 break;
tgw 0:2ee762ea11b3 303 case 'f':
tgw 0:2ee762ea11b3 304 token.type_ = tokenFalse;
tgw 0:2ee762ea11b3 305 ok = match("alse", 4);
tgw 0:2ee762ea11b3 306 break;
tgw 0:2ee762ea11b3 307 case 'n':
tgw 0:2ee762ea11b3 308 token.type_ = tokenNull;
tgw 0:2ee762ea11b3 309 ok = match("ull", 3);
tgw 0:2ee762ea11b3 310 break;
tgw 0:2ee762ea11b3 311 case ',':
tgw 0:2ee762ea11b3 312 token.type_ = tokenArraySeparator;
tgw 0:2ee762ea11b3 313 break;
tgw 0:2ee762ea11b3 314 case ':':
tgw 0:2ee762ea11b3 315 token.type_ = tokenMemberSeparator;
tgw 0:2ee762ea11b3 316 break;
tgw 0:2ee762ea11b3 317 case 0:
tgw 0:2ee762ea11b3 318 token.type_ = tokenEndOfStream;
tgw 0:2ee762ea11b3 319 break;
tgw 0:2ee762ea11b3 320 default:
tgw 0:2ee762ea11b3 321 ok = false;
tgw 0:2ee762ea11b3 322 break;
tgw 0:2ee762ea11b3 323 }
tgw 0:2ee762ea11b3 324 if (!ok)
tgw 0:2ee762ea11b3 325 token.type_ = tokenError;
tgw 0:2ee762ea11b3 326 token.end_ = current_;
tgw 0:2ee762ea11b3 327 return true;
tgw 0:2ee762ea11b3 328 }
tgw 0:2ee762ea11b3 329
tgw 0:2ee762ea11b3 330 void Reader::skipSpaces() {
tgw 0:2ee762ea11b3 331 while (current_ != end_) {
tgw 0:2ee762ea11b3 332 Char c = *current_;
tgw 0:2ee762ea11b3 333 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
tgw 0:2ee762ea11b3 334 ++current_;
tgw 0:2ee762ea11b3 335 else
tgw 0:2ee762ea11b3 336 break;
tgw 0:2ee762ea11b3 337 }
tgw 0:2ee762ea11b3 338 }
tgw 0:2ee762ea11b3 339
tgw 0:2ee762ea11b3 340 bool Reader::match(Location pattern, int patternLength) {
tgw 0:2ee762ea11b3 341 if (end_ - current_ < patternLength)
tgw 0:2ee762ea11b3 342 return false;
tgw 0:2ee762ea11b3 343 int index = patternLength;
tgw 0:2ee762ea11b3 344 while (index--)
tgw 0:2ee762ea11b3 345 if (current_[index] != pattern[index])
tgw 0:2ee762ea11b3 346 return false;
tgw 0:2ee762ea11b3 347 current_ += patternLength;
tgw 0:2ee762ea11b3 348 return true;
tgw 0:2ee762ea11b3 349 }
tgw 0:2ee762ea11b3 350
tgw 0:2ee762ea11b3 351 bool Reader::readComment() {
tgw 0:2ee762ea11b3 352 Location commentBegin = current_ - 1;
tgw 0:2ee762ea11b3 353 Char c = getNextChar();
tgw 0:2ee762ea11b3 354 bool successful = false;
tgw 0:2ee762ea11b3 355 if (c == '*')
tgw 0:2ee762ea11b3 356 successful = readCStyleComment();
tgw 0:2ee762ea11b3 357 else if (c == '/')
tgw 0:2ee762ea11b3 358 successful = readCppStyleComment();
tgw 0:2ee762ea11b3 359 if (!successful)
tgw 0:2ee762ea11b3 360 return false;
tgw 0:2ee762ea11b3 361
tgw 0:2ee762ea11b3 362 if (collectComments_) {
tgw 0:2ee762ea11b3 363 CommentPlacement placement = commentBefore;
tgw 0:2ee762ea11b3 364 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
tgw 0:2ee762ea11b3 365 if (c != '*' || !containsNewLine(commentBegin, current_))
tgw 0:2ee762ea11b3 366 placement = commentAfterOnSameLine;
tgw 0:2ee762ea11b3 367 }
tgw 0:2ee762ea11b3 368
tgw 0:2ee762ea11b3 369 addComment(commentBegin, current_, placement);
tgw 0:2ee762ea11b3 370 }
tgw 0:2ee762ea11b3 371 return true;
tgw 0:2ee762ea11b3 372 }
tgw 0:2ee762ea11b3 373
tgw 0:2ee762ea11b3 374 JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
tgw 0:2ee762ea11b3 375 JSONCPP_STRING normalized;
tgw 0:2ee762ea11b3 376 normalized.reserve(static_cast<size_t>(end - begin));
tgw 0:2ee762ea11b3 377 Reader::Location current = begin;
tgw 0:2ee762ea11b3 378 while (current != end) {
tgw 0:2ee762ea11b3 379 char c = *current++;
tgw 0:2ee762ea11b3 380 if (c == '\r') {
tgw 0:2ee762ea11b3 381 if (current != end && *current == '\n')
tgw 0:2ee762ea11b3 382 // convert dos EOL
tgw 0:2ee762ea11b3 383 ++current;
tgw 0:2ee762ea11b3 384 // convert Mac EOL
tgw 0:2ee762ea11b3 385 normalized += '\n';
tgw 0:2ee762ea11b3 386 } else {
tgw 0:2ee762ea11b3 387 normalized += c;
tgw 0:2ee762ea11b3 388 }
tgw 0:2ee762ea11b3 389 }
tgw 0:2ee762ea11b3 390 return normalized;
tgw 0:2ee762ea11b3 391 }
tgw 0:2ee762ea11b3 392
tgw 0:2ee762ea11b3 393 void
tgw 0:2ee762ea11b3 394 Reader::addComment(Location begin, Location end, CommentPlacement placement) {
tgw 0:2ee762ea11b3 395 assert(collectComments_);
tgw 0:2ee762ea11b3 396 const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
tgw 0:2ee762ea11b3 397 if (placement == commentAfterOnSameLine) {
tgw 0:2ee762ea11b3 398 assert(lastValue_ != 0);
tgw 0:2ee762ea11b3 399 lastValue_->setComment(normalized, placement);
tgw 0:2ee762ea11b3 400 } else {
tgw 0:2ee762ea11b3 401 commentsBefore_ += normalized;
tgw 0:2ee762ea11b3 402 }
tgw 0:2ee762ea11b3 403 }
tgw 0:2ee762ea11b3 404
tgw 0:2ee762ea11b3 405 bool Reader::readCStyleComment() {
tgw 0:2ee762ea11b3 406 while ((current_ + 1) < end_) {
tgw 0:2ee762ea11b3 407 Char c = getNextChar();
tgw 0:2ee762ea11b3 408 if (c == '*' && *current_ == '/')
tgw 0:2ee762ea11b3 409 break;
tgw 0:2ee762ea11b3 410 }
tgw 0:2ee762ea11b3 411 return getNextChar() == '/';
tgw 0:2ee762ea11b3 412 }
tgw 0:2ee762ea11b3 413
tgw 0:2ee762ea11b3 414 bool Reader::readCppStyleComment() {
tgw 0:2ee762ea11b3 415 while (current_ != end_) {
tgw 0:2ee762ea11b3 416 Char c = getNextChar();
tgw 0:2ee762ea11b3 417 if (c == '\n')
tgw 0:2ee762ea11b3 418 break;
tgw 0:2ee762ea11b3 419 if (c == '\r') {
tgw 0:2ee762ea11b3 420 // Consume DOS EOL. It will be normalized in addComment.
tgw 0:2ee762ea11b3 421 if (current_ != end_ && *current_ == '\n')
tgw 0:2ee762ea11b3 422 getNextChar();
tgw 0:2ee762ea11b3 423 // Break on Moc OS 9 EOL.
tgw 0:2ee762ea11b3 424 break;
tgw 0:2ee762ea11b3 425 }
tgw 0:2ee762ea11b3 426 }
tgw 0:2ee762ea11b3 427 return true;
tgw 0:2ee762ea11b3 428 }
tgw 0:2ee762ea11b3 429
tgw 0:2ee762ea11b3 430 void Reader::readNumber() {
tgw 0:2ee762ea11b3 431 const char *p = current_;
tgw 0:2ee762ea11b3 432 char c = '0'; // stopgap for already consumed character
tgw 0:2ee762ea11b3 433 // integral part
tgw 0:2ee762ea11b3 434 while (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 435 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 436 // fractional part
tgw 0:2ee762ea11b3 437 if (c == '.') {
tgw 0:2ee762ea11b3 438 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 439 while (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 440 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 441 }
tgw 0:2ee762ea11b3 442 // exponential part
tgw 0:2ee762ea11b3 443 if (c == 'e' || c == 'E') {
tgw 0:2ee762ea11b3 444 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 445 if (c == '+' || c == '-')
tgw 0:2ee762ea11b3 446 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 447 while (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 448 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 449 }
tgw 0:2ee762ea11b3 450 }
tgw 0:2ee762ea11b3 451
tgw 0:2ee762ea11b3 452 bool Reader::readString() {
tgw 0:2ee762ea11b3 453 Char c = '\0';
tgw 0:2ee762ea11b3 454 while (current_ != end_) {
tgw 0:2ee762ea11b3 455 c = getNextChar();
tgw 0:2ee762ea11b3 456 if (c == '\\')
tgw 0:2ee762ea11b3 457 getNextChar();
tgw 0:2ee762ea11b3 458 else if (c == '"')
tgw 0:2ee762ea11b3 459 break;
tgw 0:2ee762ea11b3 460 }
tgw 0:2ee762ea11b3 461 return c == '"';
tgw 0:2ee762ea11b3 462 }
tgw 0:2ee762ea11b3 463
tgw 0:2ee762ea11b3 464 bool Reader::readObject(Token& tokenStart) {
tgw 0:2ee762ea11b3 465 Token tokenName;
tgw 0:2ee762ea11b3 466 JSONCPP_STRING name;
tgw 0:2ee762ea11b3 467 Value init(objectValue);
tgw 0:2ee762ea11b3 468 currentValue().swapPayload(init);
tgw 0:2ee762ea11b3 469 currentValue().setOffsetStart(tokenStart.start_ - begin_);
tgw 0:2ee762ea11b3 470 while (readToken(tokenName)) {
tgw 0:2ee762ea11b3 471 bool initialTokenOk = true;
tgw 0:2ee762ea11b3 472 while (tokenName.type_ == tokenComment && initialTokenOk)
tgw 0:2ee762ea11b3 473 initialTokenOk = readToken(tokenName);
tgw 0:2ee762ea11b3 474 if (!initialTokenOk)
tgw 0:2ee762ea11b3 475 break;
tgw 0:2ee762ea11b3 476 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
tgw 0:2ee762ea11b3 477 return true;
tgw 0:2ee762ea11b3 478 name.clear();
tgw 0:2ee762ea11b3 479 if (tokenName.type_ == tokenString) {
tgw 0:2ee762ea11b3 480 if (!decodeString(tokenName, name))
tgw 0:2ee762ea11b3 481 return recoverFromError(tokenObjectEnd);
tgw 0:2ee762ea11b3 482 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
tgw 0:2ee762ea11b3 483 Value numberName;
tgw 0:2ee762ea11b3 484 if (!decodeNumber(tokenName, numberName))
tgw 0:2ee762ea11b3 485 return recoverFromError(tokenObjectEnd);
tgw 0:2ee762ea11b3 486 name = JSONCPP_STRING(numberName.asCString());
tgw 0:2ee762ea11b3 487 } else {
tgw 0:2ee762ea11b3 488 break;
tgw 0:2ee762ea11b3 489 }
tgw 0:2ee762ea11b3 490
tgw 0:2ee762ea11b3 491 Token colon;
tgw 0:2ee762ea11b3 492 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
tgw 0:2ee762ea11b3 493 return addErrorAndRecover(
tgw 0:2ee762ea11b3 494 "Missing ':' after object member name", colon, tokenObjectEnd);
tgw 0:2ee762ea11b3 495 }
tgw 0:2ee762ea11b3 496 Value& value = currentValue()[name];
tgw 0:2ee762ea11b3 497 nodes_.push(&value);
tgw 0:2ee762ea11b3 498 bool ok = readValue();
tgw 0:2ee762ea11b3 499 nodes_.pop();
tgw 0:2ee762ea11b3 500 if (!ok) // error already set
tgw 0:2ee762ea11b3 501 return recoverFromError(tokenObjectEnd);
tgw 0:2ee762ea11b3 502
tgw 0:2ee762ea11b3 503 Token comma;
tgw 0:2ee762ea11b3 504 if (!readToken(comma) ||
tgw 0:2ee762ea11b3 505 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
tgw 0:2ee762ea11b3 506 comma.type_ != tokenComment)) {
tgw 0:2ee762ea11b3 507 return addErrorAndRecover(
tgw 0:2ee762ea11b3 508 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
tgw 0:2ee762ea11b3 509 }
tgw 0:2ee762ea11b3 510 bool finalizeTokenOk = true;
tgw 0:2ee762ea11b3 511 while (comma.type_ == tokenComment && finalizeTokenOk)
tgw 0:2ee762ea11b3 512 finalizeTokenOk = readToken(comma);
tgw 0:2ee762ea11b3 513 if (comma.type_ == tokenObjectEnd)
tgw 0:2ee762ea11b3 514 return true;
tgw 0:2ee762ea11b3 515 }
tgw 0:2ee762ea11b3 516 return addErrorAndRecover(
tgw 0:2ee762ea11b3 517 "Missing '}' or object member name", tokenName, tokenObjectEnd);
tgw 0:2ee762ea11b3 518 }
tgw 0:2ee762ea11b3 519
tgw 0:2ee762ea11b3 520 bool Reader::readArray(Token& tokenStart) {
tgw 0:2ee762ea11b3 521 Value init(arrayValue);
tgw 0:2ee762ea11b3 522 currentValue().swapPayload(init);
tgw 0:2ee762ea11b3 523 currentValue().setOffsetStart(tokenStart.start_ - begin_);
tgw 0:2ee762ea11b3 524 skipSpaces();
tgw 0:2ee762ea11b3 525 if (current_ != end_ && *current_ == ']') // empty array
tgw 0:2ee762ea11b3 526 {
tgw 0:2ee762ea11b3 527 Token endArray;
tgw 0:2ee762ea11b3 528 readToken(endArray);
tgw 0:2ee762ea11b3 529 return true;
tgw 0:2ee762ea11b3 530 }
tgw 0:2ee762ea11b3 531 int index = 0;
tgw 0:2ee762ea11b3 532 for (;;) {
tgw 0:2ee762ea11b3 533 Value& value = currentValue()[index++];
tgw 0:2ee762ea11b3 534 nodes_.push(&value);
tgw 0:2ee762ea11b3 535 bool ok = readValue();
tgw 0:2ee762ea11b3 536 nodes_.pop();
tgw 0:2ee762ea11b3 537 if (!ok) // error already set
tgw 0:2ee762ea11b3 538 return recoverFromError(tokenArrayEnd);
tgw 0:2ee762ea11b3 539
tgw 0:2ee762ea11b3 540 Token token;
tgw 0:2ee762ea11b3 541 // Accept Comment after last item in the array.
tgw 0:2ee762ea11b3 542 ok = readToken(token);
tgw 0:2ee762ea11b3 543 while (token.type_ == tokenComment && ok) {
tgw 0:2ee762ea11b3 544 ok = readToken(token);
tgw 0:2ee762ea11b3 545 }
tgw 0:2ee762ea11b3 546 bool badTokenType =
tgw 0:2ee762ea11b3 547 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
tgw 0:2ee762ea11b3 548 if (!ok || badTokenType) {
tgw 0:2ee762ea11b3 549 return addErrorAndRecover(
tgw 0:2ee762ea11b3 550 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
tgw 0:2ee762ea11b3 551 }
tgw 0:2ee762ea11b3 552 if (token.type_ == tokenArrayEnd)
tgw 0:2ee762ea11b3 553 break;
tgw 0:2ee762ea11b3 554 }
tgw 0:2ee762ea11b3 555 return true;
tgw 0:2ee762ea11b3 556 }
tgw 0:2ee762ea11b3 557
tgw 0:2ee762ea11b3 558 bool Reader::decodeNumber(Token& token) {
tgw 0:2ee762ea11b3 559 Value decoded;
tgw 0:2ee762ea11b3 560 if (!decodeNumber(token, decoded))
tgw 0:2ee762ea11b3 561 return false;
tgw 0:2ee762ea11b3 562 currentValue().swapPayload(decoded);
tgw 0:2ee762ea11b3 563 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 564 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 565 return true;
tgw 0:2ee762ea11b3 566 }
tgw 0:2ee762ea11b3 567
tgw 0:2ee762ea11b3 568 bool Reader::decodeNumber(Token& token, Value& decoded) {
tgw 0:2ee762ea11b3 569 // Attempts to parse the number as an integer. If the number is
tgw 0:2ee762ea11b3 570 // larger than the maximum supported value of an integer then
tgw 0:2ee762ea11b3 571 // we decode the number as a double.
tgw 0:2ee762ea11b3 572 Location current = token.start_;
tgw 0:2ee762ea11b3 573 bool isNegative = *current == '-';
tgw 0:2ee762ea11b3 574 if (isNegative)
tgw 0:2ee762ea11b3 575 ++current;
tgw 0:2ee762ea11b3 576 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
tgw 0:2ee762ea11b3 577 Value::LargestUInt maxIntegerValue =
tgw 0:2ee762ea11b3 578 isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
tgw 0:2ee762ea11b3 579 : Value::maxLargestUInt;
tgw 0:2ee762ea11b3 580 Value::LargestUInt threshold = maxIntegerValue / 10;
tgw 0:2ee762ea11b3 581 Value::LargestUInt value = 0;
tgw 0:2ee762ea11b3 582 while (current < token.end_) {
tgw 0:2ee762ea11b3 583 Char c = *current++;
tgw 0:2ee762ea11b3 584 if (c < '0' || c > '9')
tgw 0:2ee762ea11b3 585 return decodeDouble(token, decoded);
tgw 0:2ee762ea11b3 586 Value::UInt digit(static_cast<Value::UInt>(c - '0'));
tgw 0:2ee762ea11b3 587 if (value >= threshold) {
tgw 0:2ee762ea11b3 588 // We've hit or exceeded the max value divided by 10 (rounded down). If
tgw 0:2ee762ea11b3 589 // a) we've only just touched the limit, b) this is the last digit, and
tgw 0:2ee762ea11b3 590 // c) it's small enough to fit in that rounding delta, we're okay.
tgw 0:2ee762ea11b3 591 // Otherwise treat this number as a double to avoid overflow.
tgw 0:2ee762ea11b3 592 if (value > threshold || current != token.end_ ||
tgw 0:2ee762ea11b3 593 digit > maxIntegerValue % 10) {
tgw 0:2ee762ea11b3 594 return decodeDouble(token, decoded);
tgw 0:2ee762ea11b3 595 }
tgw 0:2ee762ea11b3 596 }
tgw 0:2ee762ea11b3 597 value = value * 10 + digit;
tgw 0:2ee762ea11b3 598 }
tgw 0:2ee762ea11b3 599 if (isNegative && value == maxIntegerValue)
tgw 0:2ee762ea11b3 600 decoded = Value::minLargestInt;
tgw 0:2ee762ea11b3 601 else if (isNegative)
tgw 0:2ee762ea11b3 602 decoded = -Value::LargestInt(value);
tgw 0:2ee762ea11b3 603 else if (value <= Value::LargestUInt(Value::maxInt))
tgw 0:2ee762ea11b3 604 decoded = Value::LargestInt(value);
tgw 0:2ee762ea11b3 605 else
tgw 0:2ee762ea11b3 606 decoded = value;
tgw 0:2ee762ea11b3 607 return true;
tgw 0:2ee762ea11b3 608 }
tgw 0:2ee762ea11b3 609
tgw 0:2ee762ea11b3 610 bool Reader::decodeDouble(Token& token) {
tgw 0:2ee762ea11b3 611 Value decoded;
tgw 0:2ee762ea11b3 612 if (!decodeDouble(token, decoded))
tgw 0:2ee762ea11b3 613 return false;
tgw 0:2ee762ea11b3 614 currentValue().swapPayload(decoded);
tgw 0:2ee762ea11b3 615 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 616 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 617 return true;
tgw 0:2ee762ea11b3 618 }
tgw 0:2ee762ea11b3 619
tgw 0:2ee762ea11b3 620 bool Reader::decodeDouble(Token& token, Value& decoded) {
tgw 0:2ee762ea11b3 621 double value = 0;
tgw 0:2ee762ea11b3 622 JSONCPP_STRING buffer(token.start_, token.end_);
tgw 0:2ee762ea11b3 623 JSONCPP_ISTRINGSTREAM is(buffer);
tgw 0:2ee762ea11b3 624 if (!(is >> value))
tgw 0:2ee762ea11b3 625 return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
tgw 0:2ee762ea11b3 626 "' is not a number.",
tgw 0:2ee762ea11b3 627 token);
tgw 0:2ee762ea11b3 628 decoded = value;
tgw 0:2ee762ea11b3 629 return true;
tgw 0:2ee762ea11b3 630 }
tgw 0:2ee762ea11b3 631
tgw 0:2ee762ea11b3 632 bool Reader::decodeString(Token& token) {
tgw 0:2ee762ea11b3 633 JSONCPP_STRING decoded_string;
tgw 0:2ee762ea11b3 634 if (!decodeString(token, decoded_string))
tgw 0:2ee762ea11b3 635 return false;
tgw 0:2ee762ea11b3 636 Value decoded(decoded_string);
tgw 0:2ee762ea11b3 637 currentValue().swapPayload(decoded);
tgw 0:2ee762ea11b3 638 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 639 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 640 return true;
tgw 0:2ee762ea11b3 641 }
tgw 0:2ee762ea11b3 642
tgw 0:2ee762ea11b3 643 bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) {
tgw 0:2ee762ea11b3 644 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
tgw 0:2ee762ea11b3 645 Location current = token.start_ + 1; // skip '"'
tgw 0:2ee762ea11b3 646 Location end = token.end_ - 1; // do not include '"'
tgw 0:2ee762ea11b3 647 while (current != end) {
tgw 0:2ee762ea11b3 648 Char c = *current++;
tgw 0:2ee762ea11b3 649 if (c == '"')
tgw 0:2ee762ea11b3 650 break;
tgw 0:2ee762ea11b3 651 else if (c == '\\') {
tgw 0:2ee762ea11b3 652 if (current == end)
tgw 0:2ee762ea11b3 653 return addError("Empty escape sequence in string", token, current);
tgw 0:2ee762ea11b3 654 Char escape = *current++;
tgw 0:2ee762ea11b3 655 switch (escape) {
tgw 0:2ee762ea11b3 656 case '"':
tgw 0:2ee762ea11b3 657 decoded += '"';
tgw 0:2ee762ea11b3 658 break;
tgw 0:2ee762ea11b3 659 case '/':
tgw 0:2ee762ea11b3 660 decoded += '/';
tgw 0:2ee762ea11b3 661 break;
tgw 0:2ee762ea11b3 662 case '\\':
tgw 0:2ee762ea11b3 663 decoded += '\\';
tgw 0:2ee762ea11b3 664 break;
tgw 0:2ee762ea11b3 665 case 'b':
tgw 0:2ee762ea11b3 666 decoded += '\b';
tgw 0:2ee762ea11b3 667 break;
tgw 0:2ee762ea11b3 668 case 'f':
tgw 0:2ee762ea11b3 669 decoded += '\f';
tgw 0:2ee762ea11b3 670 break;
tgw 0:2ee762ea11b3 671 case 'n':
tgw 0:2ee762ea11b3 672 decoded += '\n';
tgw 0:2ee762ea11b3 673 break;
tgw 0:2ee762ea11b3 674 case 'r':
tgw 0:2ee762ea11b3 675 decoded += '\r';
tgw 0:2ee762ea11b3 676 break;
tgw 0:2ee762ea11b3 677 case 't':
tgw 0:2ee762ea11b3 678 decoded += '\t';
tgw 0:2ee762ea11b3 679 break;
tgw 0:2ee762ea11b3 680 case 'u': {
tgw 0:2ee762ea11b3 681 unsigned int unicode;
tgw 0:2ee762ea11b3 682 if (!decodeUnicodeCodePoint(token, current, end, unicode))
tgw 0:2ee762ea11b3 683 return false;
tgw 0:2ee762ea11b3 684 decoded += codePointToUTF8(unicode);
tgw 0:2ee762ea11b3 685 } break;
tgw 0:2ee762ea11b3 686 default:
tgw 0:2ee762ea11b3 687 return addError("Bad escape sequence in string", token, current);
tgw 0:2ee762ea11b3 688 }
tgw 0:2ee762ea11b3 689 } else {
tgw 0:2ee762ea11b3 690 decoded += c;
tgw 0:2ee762ea11b3 691 }
tgw 0:2ee762ea11b3 692 }
tgw 0:2ee762ea11b3 693 return true;
tgw 0:2ee762ea11b3 694 }
tgw 0:2ee762ea11b3 695
tgw 0:2ee762ea11b3 696 bool Reader::decodeUnicodeCodePoint(Token& token,
tgw 0:2ee762ea11b3 697 Location& current,
tgw 0:2ee762ea11b3 698 Location end,
tgw 0:2ee762ea11b3 699 unsigned int& unicode) {
tgw 0:2ee762ea11b3 700
tgw 0:2ee762ea11b3 701 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
tgw 0:2ee762ea11b3 702 return false;
tgw 0:2ee762ea11b3 703 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
tgw 0:2ee762ea11b3 704 // surrogate pairs
tgw 0:2ee762ea11b3 705 if (end - current < 6)
tgw 0:2ee762ea11b3 706 return addError(
tgw 0:2ee762ea11b3 707 "additional six characters expected to parse unicode surrogate pair.",
tgw 0:2ee762ea11b3 708 token,
tgw 0:2ee762ea11b3 709 current);
tgw 0:2ee762ea11b3 710 unsigned int surrogatePair;
tgw 0:2ee762ea11b3 711 if (*(current++) == '\\' && *(current++) == 'u') {
tgw 0:2ee762ea11b3 712 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
tgw 0:2ee762ea11b3 713 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
tgw 0:2ee762ea11b3 714 } else
tgw 0:2ee762ea11b3 715 return false;
tgw 0:2ee762ea11b3 716 } else
tgw 0:2ee762ea11b3 717 return addError("expecting another \\u token to begin the second half of "
tgw 0:2ee762ea11b3 718 "a unicode surrogate pair",
tgw 0:2ee762ea11b3 719 token,
tgw 0:2ee762ea11b3 720 current);
tgw 0:2ee762ea11b3 721 }
tgw 0:2ee762ea11b3 722 return true;
tgw 0:2ee762ea11b3 723 }
tgw 0:2ee762ea11b3 724
tgw 0:2ee762ea11b3 725 bool Reader::decodeUnicodeEscapeSequence(Token& token,
tgw 0:2ee762ea11b3 726 Location& current,
tgw 0:2ee762ea11b3 727 Location end,
tgw 0:2ee762ea11b3 728 unsigned int& ret_unicode) {
tgw 0:2ee762ea11b3 729 if (end - current < 4)
tgw 0:2ee762ea11b3 730 return addError(
tgw 0:2ee762ea11b3 731 "Bad unicode escape sequence in string: four digits expected.",
tgw 0:2ee762ea11b3 732 token,
tgw 0:2ee762ea11b3 733 current);
tgw 0:2ee762ea11b3 734 int unicode = 0;
tgw 0:2ee762ea11b3 735 for (int index = 0; index < 4; ++index) {
tgw 0:2ee762ea11b3 736 Char c = *current++;
tgw 0:2ee762ea11b3 737 unicode *= 16;
tgw 0:2ee762ea11b3 738 if (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 739 unicode += c - '0';
tgw 0:2ee762ea11b3 740 else if (c >= 'a' && c <= 'f')
tgw 0:2ee762ea11b3 741 unicode += c - 'a' + 10;
tgw 0:2ee762ea11b3 742 else if (c >= 'A' && c <= 'F')
tgw 0:2ee762ea11b3 743 unicode += c - 'A' + 10;
tgw 0:2ee762ea11b3 744 else
tgw 0:2ee762ea11b3 745 return addError(
tgw 0:2ee762ea11b3 746 "Bad unicode escape sequence in string: hexadecimal digit expected.",
tgw 0:2ee762ea11b3 747 token,
tgw 0:2ee762ea11b3 748 current);
tgw 0:2ee762ea11b3 749 }
tgw 0:2ee762ea11b3 750 ret_unicode = static_cast<unsigned int>(unicode);
tgw 0:2ee762ea11b3 751 return true;
tgw 0:2ee762ea11b3 752 }
tgw 0:2ee762ea11b3 753
tgw 0:2ee762ea11b3 754 bool
tgw 0:2ee762ea11b3 755 Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
tgw 0:2ee762ea11b3 756 ErrorInfo info;
tgw 0:2ee762ea11b3 757 info.token_ = token;
tgw 0:2ee762ea11b3 758 info.message_ = message;
tgw 0:2ee762ea11b3 759 info.extra_ = extra;
tgw 0:2ee762ea11b3 760 errors_.push_back(info);
tgw 0:2ee762ea11b3 761 return false;
tgw 0:2ee762ea11b3 762 }
tgw 0:2ee762ea11b3 763
tgw 0:2ee762ea11b3 764 bool Reader::recoverFromError(TokenType skipUntilToken) {
tgw 0:2ee762ea11b3 765 size_t const errorCount = errors_.size();
tgw 0:2ee762ea11b3 766 Token skip;
tgw 0:2ee762ea11b3 767 for (;;) {
tgw 0:2ee762ea11b3 768 if (!readToken(skip))
tgw 0:2ee762ea11b3 769 errors_.resize(errorCount); // discard errors caused by recovery
tgw 0:2ee762ea11b3 770 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
tgw 0:2ee762ea11b3 771 break;
tgw 0:2ee762ea11b3 772 }
tgw 0:2ee762ea11b3 773 errors_.resize(errorCount);
tgw 0:2ee762ea11b3 774 return false;
tgw 0:2ee762ea11b3 775 }
tgw 0:2ee762ea11b3 776
tgw 0:2ee762ea11b3 777 bool Reader::addErrorAndRecover(const JSONCPP_STRING& message,
tgw 0:2ee762ea11b3 778 Token& token,
tgw 0:2ee762ea11b3 779 TokenType skipUntilToken) {
tgw 0:2ee762ea11b3 780 addError(message, token);
tgw 0:2ee762ea11b3 781 return recoverFromError(skipUntilToken);
tgw 0:2ee762ea11b3 782 }
tgw 0:2ee762ea11b3 783
tgw 0:2ee762ea11b3 784 Value& Reader::currentValue() { return *(nodes_.top()); }
tgw 0:2ee762ea11b3 785
tgw 0:2ee762ea11b3 786 Reader::Char Reader::getNextChar() {
tgw 0:2ee762ea11b3 787 if (current_ == end_)
tgw 0:2ee762ea11b3 788 return 0;
tgw 0:2ee762ea11b3 789 return *current_++;
tgw 0:2ee762ea11b3 790 }
tgw 0:2ee762ea11b3 791
tgw 0:2ee762ea11b3 792 void Reader::getLocationLineAndColumn(Location location,
tgw 0:2ee762ea11b3 793 int& line,
tgw 0:2ee762ea11b3 794 int& column) const {
tgw 0:2ee762ea11b3 795 Location current = begin_;
tgw 0:2ee762ea11b3 796 Location lastLineStart = current;
tgw 0:2ee762ea11b3 797 line = 0;
tgw 0:2ee762ea11b3 798 while (current < location && current != end_) {
tgw 0:2ee762ea11b3 799 Char c = *current++;
tgw 0:2ee762ea11b3 800 if (c == '\r') {
tgw 0:2ee762ea11b3 801 if (*current == '\n')
tgw 0:2ee762ea11b3 802 ++current;
tgw 0:2ee762ea11b3 803 lastLineStart = current;
tgw 0:2ee762ea11b3 804 ++line;
tgw 0:2ee762ea11b3 805 } else if (c == '\n') {
tgw 0:2ee762ea11b3 806 lastLineStart = current;
tgw 0:2ee762ea11b3 807 ++line;
tgw 0:2ee762ea11b3 808 }
tgw 0:2ee762ea11b3 809 }
tgw 0:2ee762ea11b3 810 // column & line start at 1
tgw 0:2ee762ea11b3 811 column = int(location - lastLineStart) + 1;
tgw 0:2ee762ea11b3 812 ++line;
tgw 0:2ee762ea11b3 813 }
tgw 0:2ee762ea11b3 814
tgw 0:2ee762ea11b3 815 JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const {
tgw 0:2ee762ea11b3 816 int line, column;
tgw 0:2ee762ea11b3 817 getLocationLineAndColumn(location, line, column);
tgw 0:2ee762ea11b3 818 char buffer[18 + 16 + 16 + 1];
tgw 0:2ee762ea11b3 819 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
tgw 0:2ee762ea11b3 820 return buffer;
tgw 0:2ee762ea11b3 821 }
tgw 0:2ee762ea11b3 822
tgw 0:2ee762ea11b3 823 // Deprecated. Preserved for backward compatibility
tgw 0:2ee762ea11b3 824 JSONCPP_STRING Reader::getFormatedErrorMessages() const {
tgw 0:2ee762ea11b3 825 return getFormattedErrorMessages();
tgw 0:2ee762ea11b3 826 }
tgw 0:2ee762ea11b3 827
tgw 0:2ee762ea11b3 828 JSONCPP_STRING Reader::getFormattedErrorMessages() const {
tgw 0:2ee762ea11b3 829 JSONCPP_STRING formattedMessage;
tgw 0:2ee762ea11b3 830 for (Errors::const_iterator itError = errors_.begin();
tgw 0:2ee762ea11b3 831 itError != errors_.end();
tgw 0:2ee762ea11b3 832 ++itError) {
tgw 0:2ee762ea11b3 833 const ErrorInfo& error = *itError;
tgw 0:2ee762ea11b3 834 formattedMessage +=
tgw 0:2ee762ea11b3 835 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
tgw 0:2ee762ea11b3 836 formattedMessage += " " + error.message_ + "\n";
tgw 0:2ee762ea11b3 837 if (error.extra_)
tgw 0:2ee762ea11b3 838 formattedMessage +=
tgw 0:2ee762ea11b3 839 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
tgw 0:2ee762ea11b3 840 }
tgw 0:2ee762ea11b3 841 return formattedMessage;
tgw 0:2ee762ea11b3 842 }
tgw 0:2ee762ea11b3 843
tgw 0:2ee762ea11b3 844 std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
tgw 0:2ee762ea11b3 845 std::vector<Reader::StructuredError> allErrors;
tgw 0:2ee762ea11b3 846 for (Errors::const_iterator itError = errors_.begin();
tgw 0:2ee762ea11b3 847 itError != errors_.end();
tgw 0:2ee762ea11b3 848 ++itError) {
tgw 0:2ee762ea11b3 849 const ErrorInfo& error = *itError;
tgw 0:2ee762ea11b3 850 Reader::StructuredError structured;
tgw 0:2ee762ea11b3 851 structured.offset_start = error.token_.start_ - begin_;
tgw 0:2ee762ea11b3 852 structured.offset_limit = error.token_.end_ - begin_;
tgw 0:2ee762ea11b3 853 structured.message = error.message_;
tgw 0:2ee762ea11b3 854 allErrors.push_back(structured);
tgw 0:2ee762ea11b3 855 }
tgw 0:2ee762ea11b3 856 return allErrors;
tgw 0:2ee762ea11b3 857 }
tgw 0:2ee762ea11b3 858
tgw 0:2ee762ea11b3 859 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) {
tgw 0:2ee762ea11b3 860 ptrdiff_t const length = end_ - begin_;
tgw 0:2ee762ea11b3 861 if(value.getOffsetStart() > length
tgw 0:2ee762ea11b3 862 || value.getOffsetLimit() > length)
tgw 0:2ee762ea11b3 863 return false;
tgw 0:2ee762ea11b3 864 Token token;
tgw 0:2ee762ea11b3 865 token.type_ = tokenError;
tgw 0:2ee762ea11b3 866 token.start_ = begin_ + value.getOffsetStart();
tgw 0:2ee762ea11b3 867 token.end_ = end_ + value.getOffsetLimit();
tgw 0:2ee762ea11b3 868 ErrorInfo info;
tgw 0:2ee762ea11b3 869 info.token_ = token;
tgw 0:2ee762ea11b3 870 info.message_ = message;
tgw 0:2ee762ea11b3 871 info.extra_ = 0;
tgw 0:2ee762ea11b3 872 errors_.push_back(info);
tgw 0:2ee762ea11b3 873 return true;
tgw 0:2ee762ea11b3 874 }
tgw 0:2ee762ea11b3 875
tgw 0:2ee762ea11b3 876 bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
tgw 0:2ee762ea11b3 877 ptrdiff_t const length = end_ - begin_;
tgw 0:2ee762ea11b3 878 if(value.getOffsetStart() > length
tgw 0:2ee762ea11b3 879 || value.getOffsetLimit() > length
tgw 0:2ee762ea11b3 880 || extra.getOffsetLimit() > length)
tgw 0:2ee762ea11b3 881 return false;
tgw 0:2ee762ea11b3 882 Token token;
tgw 0:2ee762ea11b3 883 token.type_ = tokenError;
tgw 0:2ee762ea11b3 884 token.start_ = begin_ + value.getOffsetStart();
tgw 0:2ee762ea11b3 885 token.end_ = begin_ + value.getOffsetLimit();
tgw 0:2ee762ea11b3 886 ErrorInfo info;
tgw 0:2ee762ea11b3 887 info.token_ = token;
tgw 0:2ee762ea11b3 888 info.message_ = message;
tgw 0:2ee762ea11b3 889 info.extra_ = begin_ + extra.getOffsetStart();
tgw 0:2ee762ea11b3 890 errors_.push_back(info);
tgw 0:2ee762ea11b3 891 return true;
tgw 0:2ee762ea11b3 892 }
tgw 0:2ee762ea11b3 893
tgw 0:2ee762ea11b3 894 bool Reader::good() const {
tgw 0:2ee762ea11b3 895 return !errors_.size();
tgw 0:2ee762ea11b3 896 }
tgw 0:2ee762ea11b3 897
tgw 0:2ee762ea11b3 898 // exact copy of Features
tgw 0:2ee762ea11b3 899 class OurFeatures {
tgw 0:2ee762ea11b3 900 public:
tgw 0:2ee762ea11b3 901 static OurFeatures all();
tgw 0:2ee762ea11b3 902 bool allowComments_;
tgw 0:2ee762ea11b3 903 bool strictRoot_;
tgw 0:2ee762ea11b3 904 bool allowDroppedNullPlaceholders_;
tgw 0:2ee762ea11b3 905 bool allowNumericKeys_;
tgw 0:2ee762ea11b3 906 bool allowSingleQuotes_;
tgw 0:2ee762ea11b3 907 bool failIfExtra_;
tgw 0:2ee762ea11b3 908 bool rejectDupKeys_;
tgw 0:2ee762ea11b3 909 bool allowSpecialFloats_;
tgw 0:2ee762ea11b3 910 int stackLimit_;
tgw 0:2ee762ea11b3 911 }; // OurFeatures
tgw 0:2ee762ea11b3 912
tgw 0:2ee762ea11b3 913 // exact copy of Implementation of class Features
tgw 0:2ee762ea11b3 914 // ////////////////////////////////
tgw 0:2ee762ea11b3 915
tgw 0:2ee762ea11b3 916 OurFeatures OurFeatures::all() { return OurFeatures(); }
tgw 0:2ee762ea11b3 917
tgw 0:2ee762ea11b3 918 // Implementation of class Reader
tgw 0:2ee762ea11b3 919 // ////////////////////////////////
tgw 0:2ee762ea11b3 920
tgw 0:2ee762ea11b3 921 // exact copy of Reader, renamed to OurReader
tgw 0:2ee762ea11b3 922 class OurReader {
tgw 0:2ee762ea11b3 923 public:
tgw 0:2ee762ea11b3 924 typedef char Char;
tgw 0:2ee762ea11b3 925 typedef const Char* Location;
tgw 0:2ee762ea11b3 926 struct StructuredError {
tgw 0:2ee762ea11b3 927 ptrdiff_t offset_start;
tgw 0:2ee762ea11b3 928 ptrdiff_t offset_limit;
tgw 0:2ee762ea11b3 929 JSONCPP_STRING message;
tgw 0:2ee762ea11b3 930 };
tgw 0:2ee762ea11b3 931
tgw 0:2ee762ea11b3 932 OurReader(OurFeatures const& features);
tgw 0:2ee762ea11b3 933 bool parse(const char* beginDoc,
tgw 0:2ee762ea11b3 934 const char* endDoc,
tgw 0:2ee762ea11b3 935 Value& root,
tgw 0:2ee762ea11b3 936 bool collectComments = true);
tgw 0:2ee762ea11b3 937 JSONCPP_STRING getFormattedErrorMessages() const;
tgw 0:2ee762ea11b3 938 std::vector<StructuredError> getStructuredErrors() const;
tgw 0:2ee762ea11b3 939 bool pushError(const Value& value, const JSONCPP_STRING& message);
tgw 0:2ee762ea11b3 940 bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra);
tgw 0:2ee762ea11b3 941 bool good() const;
tgw 0:2ee762ea11b3 942
tgw 0:2ee762ea11b3 943 private:
tgw 0:2ee762ea11b3 944 OurReader(OurReader const&); // no impl
tgw 0:2ee762ea11b3 945 void operator=(OurReader const&); // no impl
tgw 0:2ee762ea11b3 946
tgw 0:2ee762ea11b3 947 enum TokenType {
tgw 0:2ee762ea11b3 948 tokenEndOfStream = 0,
tgw 0:2ee762ea11b3 949 tokenObjectBegin,
tgw 0:2ee762ea11b3 950 tokenObjectEnd,
tgw 0:2ee762ea11b3 951 tokenArrayBegin,
tgw 0:2ee762ea11b3 952 tokenArrayEnd,
tgw 0:2ee762ea11b3 953 tokenString,
tgw 0:2ee762ea11b3 954 tokenNumber,
tgw 0:2ee762ea11b3 955 tokenTrue,
tgw 0:2ee762ea11b3 956 tokenFalse,
tgw 0:2ee762ea11b3 957 tokenNull,
tgw 0:2ee762ea11b3 958 tokenNaN,
tgw 0:2ee762ea11b3 959 tokenPosInf,
tgw 0:2ee762ea11b3 960 tokenNegInf,
tgw 0:2ee762ea11b3 961 tokenArraySeparator,
tgw 0:2ee762ea11b3 962 tokenMemberSeparator,
tgw 0:2ee762ea11b3 963 tokenComment,
tgw 0:2ee762ea11b3 964 tokenError
tgw 0:2ee762ea11b3 965 };
tgw 0:2ee762ea11b3 966
tgw 0:2ee762ea11b3 967 class Token {
tgw 0:2ee762ea11b3 968 public:
tgw 0:2ee762ea11b3 969 TokenType type_;
tgw 0:2ee762ea11b3 970 Location start_;
tgw 0:2ee762ea11b3 971 Location end_;
tgw 0:2ee762ea11b3 972 };
tgw 0:2ee762ea11b3 973
tgw 0:2ee762ea11b3 974 class ErrorInfo {
tgw 0:2ee762ea11b3 975 public:
tgw 0:2ee762ea11b3 976 Token token_;
tgw 0:2ee762ea11b3 977 JSONCPP_STRING message_;
tgw 0:2ee762ea11b3 978 Location extra_;
tgw 0:2ee762ea11b3 979 };
tgw 0:2ee762ea11b3 980
tgw 0:2ee762ea11b3 981 typedef std::deque<ErrorInfo> Errors;
tgw 0:2ee762ea11b3 982
tgw 0:2ee762ea11b3 983 bool readToken(Token& token);
tgw 0:2ee762ea11b3 984 void skipSpaces();
tgw 0:2ee762ea11b3 985 bool match(Location pattern, int patternLength);
tgw 0:2ee762ea11b3 986 bool readComment();
tgw 0:2ee762ea11b3 987 bool readCStyleComment();
tgw 0:2ee762ea11b3 988 bool readCppStyleComment();
tgw 0:2ee762ea11b3 989 bool readString();
tgw 0:2ee762ea11b3 990 bool readStringSingleQuote();
tgw 0:2ee762ea11b3 991 bool readNumber(bool checkInf);
tgw 0:2ee762ea11b3 992 bool readValue();
tgw 0:2ee762ea11b3 993 bool readObject(Token& token);
tgw 0:2ee762ea11b3 994 bool readArray(Token& token);
tgw 0:2ee762ea11b3 995 bool decodeNumber(Token& token);
tgw 0:2ee762ea11b3 996 bool decodeNumber(Token& token, Value& decoded);
tgw 0:2ee762ea11b3 997 bool decodeString(Token& token);
tgw 0:2ee762ea11b3 998 bool decodeString(Token& token, JSONCPP_STRING& decoded);
tgw 0:2ee762ea11b3 999 bool decodeDouble(Token& token);
tgw 0:2ee762ea11b3 1000 bool decodeDouble(Token& token, Value& decoded);
tgw 0:2ee762ea11b3 1001 bool decodeUnicodeCodePoint(Token& token,
tgw 0:2ee762ea11b3 1002 Location& current,
tgw 0:2ee762ea11b3 1003 Location end,
tgw 0:2ee762ea11b3 1004 unsigned int& unicode);
tgw 0:2ee762ea11b3 1005 bool decodeUnicodeEscapeSequence(Token& token,
tgw 0:2ee762ea11b3 1006 Location& current,
tgw 0:2ee762ea11b3 1007 Location end,
tgw 0:2ee762ea11b3 1008 unsigned int& unicode);
tgw 0:2ee762ea11b3 1009 bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0);
tgw 0:2ee762ea11b3 1010 bool recoverFromError(TokenType skipUntilToken);
tgw 0:2ee762ea11b3 1011 bool addErrorAndRecover(const JSONCPP_STRING& message,
tgw 0:2ee762ea11b3 1012 Token& token,
tgw 0:2ee762ea11b3 1013 TokenType skipUntilToken);
tgw 0:2ee762ea11b3 1014 void skipUntilSpace();
tgw 0:2ee762ea11b3 1015 Value& currentValue();
tgw 0:2ee762ea11b3 1016 Char getNextChar();
tgw 0:2ee762ea11b3 1017 void
tgw 0:2ee762ea11b3 1018 getLocationLineAndColumn(Location location, int& line, int& column) const;
tgw 0:2ee762ea11b3 1019 JSONCPP_STRING getLocationLineAndColumn(Location location) const;
tgw 0:2ee762ea11b3 1020 void addComment(Location begin, Location end, CommentPlacement placement);
tgw 0:2ee762ea11b3 1021 void skipCommentTokens(Token& token);
tgw 0:2ee762ea11b3 1022
tgw 0:2ee762ea11b3 1023 static JSONCPP_STRING normalizeEOL(Location begin, Location end);
tgw 0:2ee762ea11b3 1024 static bool containsNewLine(Location begin, Location end);
tgw 0:2ee762ea11b3 1025
tgw 0:2ee762ea11b3 1026 typedef std::stack<Value*> Nodes;
tgw 0:2ee762ea11b3 1027 Nodes nodes_;
tgw 0:2ee762ea11b3 1028 Errors errors_;
tgw 0:2ee762ea11b3 1029 JSONCPP_STRING document_;
tgw 0:2ee762ea11b3 1030 Location begin_;
tgw 0:2ee762ea11b3 1031 Location end_;
tgw 0:2ee762ea11b3 1032 Location current_;
tgw 0:2ee762ea11b3 1033 Location lastValueEnd_;
tgw 0:2ee762ea11b3 1034 Value* lastValue_;
tgw 0:2ee762ea11b3 1035 JSONCPP_STRING commentsBefore_;
tgw 0:2ee762ea11b3 1036
tgw 0:2ee762ea11b3 1037 OurFeatures const features_;
tgw 0:2ee762ea11b3 1038 bool collectComments_;
tgw 0:2ee762ea11b3 1039 }; // OurReader
tgw 0:2ee762ea11b3 1040
tgw 0:2ee762ea11b3 1041 // complete copy of Read impl, for OurReader
tgw 0:2ee762ea11b3 1042
tgw 0:2ee762ea11b3 1043 bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) {
tgw 0:2ee762ea11b3 1044 for (; begin < end; ++begin)
tgw 0:2ee762ea11b3 1045 if (*begin == '\n' || *begin == '\r')
tgw 0:2ee762ea11b3 1046 return true;
tgw 0:2ee762ea11b3 1047 return false;
tgw 0:2ee762ea11b3 1048 }
tgw 0:2ee762ea11b3 1049
tgw 0:2ee762ea11b3 1050 OurReader::OurReader(OurFeatures const& features)
tgw 0:2ee762ea11b3 1051 : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
tgw 0:2ee762ea11b3 1052 lastValue_(), commentsBefore_(),
tgw 0:2ee762ea11b3 1053 features_(features), collectComments_() {
tgw 0:2ee762ea11b3 1054 }
tgw 0:2ee762ea11b3 1055
tgw 0:2ee762ea11b3 1056 bool OurReader::parse(const char* beginDoc,
tgw 0:2ee762ea11b3 1057 const char* endDoc,
tgw 0:2ee762ea11b3 1058 Value& root,
tgw 0:2ee762ea11b3 1059 bool collectComments) {
tgw 0:2ee762ea11b3 1060 if (!features_.allowComments_) {
tgw 0:2ee762ea11b3 1061 collectComments = false;
tgw 0:2ee762ea11b3 1062 }
tgw 0:2ee762ea11b3 1063
tgw 0:2ee762ea11b3 1064 begin_ = beginDoc;
tgw 0:2ee762ea11b3 1065 end_ = endDoc;
tgw 0:2ee762ea11b3 1066 collectComments_ = collectComments;
tgw 0:2ee762ea11b3 1067 current_ = begin_;
tgw 0:2ee762ea11b3 1068 lastValueEnd_ = 0;
tgw 0:2ee762ea11b3 1069 lastValue_ = 0;
tgw 0:2ee762ea11b3 1070 commentsBefore_.clear();
tgw 0:2ee762ea11b3 1071 errors_.clear();
tgw 0:2ee762ea11b3 1072 while (!nodes_.empty())
tgw 0:2ee762ea11b3 1073 nodes_.pop();
tgw 0:2ee762ea11b3 1074 nodes_.push(&root);
tgw 0:2ee762ea11b3 1075
tgw 0:2ee762ea11b3 1076 bool successful = readValue();
tgw 0:2ee762ea11b3 1077 Token token;
tgw 0:2ee762ea11b3 1078 skipCommentTokens(token);
tgw 0:2ee762ea11b3 1079 if (features_.failIfExtra_) {
tgw 0:2ee762ea11b3 1080 if ((features_.strictRoot_ || token.type_ != tokenError) && token.type_ != tokenEndOfStream) {
tgw 0:2ee762ea11b3 1081 addError("Extra non-whitespace after JSON value.", token);
tgw 0:2ee762ea11b3 1082 return false;
tgw 0:2ee762ea11b3 1083 }
tgw 0:2ee762ea11b3 1084 }
tgw 0:2ee762ea11b3 1085 if (collectComments_ && !commentsBefore_.empty())
tgw 0:2ee762ea11b3 1086 root.setComment(commentsBefore_, commentAfter);
tgw 0:2ee762ea11b3 1087 if (features_.strictRoot_) {
tgw 0:2ee762ea11b3 1088 if (!root.isArray() && !root.isObject()) {
tgw 0:2ee762ea11b3 1089 // Set error location to start of doc, ideally should be first token found
tgw 0:2ee762ea11b3 1090 // in doc
tgw 0:2ee762ea11b3 1091 token.type_ = tokenError;
tgw 0:2ee762ea11b3 1092 token.start_ = beginDoc;
tgw 0:2ee762ea11b3 1093 token.end_ = endDoc;
tgw 0:2ee762ea11b3 1094 addError(
tgw 0:2ee762ea11b3 1095 "A valid JSON document must be either an array or an object value.",
tgw 0:2ee762ea11b3 1096 token);
tgw 0:2ee762ea11b3 1097 return false;
tgw 0:2ee762ea11b3 1098 }
tgw 0:2ee762ea11b3 1099 }
tgw 0:2ee762ea11b3 1100 return successful;
tgw 0:2ee762ea11b3 1101 }
tgw 0:2ee762ea11b3 1102
tgw 0:2ee762ea11b3 1103 bool OurReader::readValue() {
tgw 0:2ee762ea11b3 1104 // To preserve the old behaviour we cast size_t to int.
tgw 0:2ee762ea11b3 1105 if (static_cast<int>(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue().");
tgw 0:2ee762ea11b3 1106 Token token;
tgw 0:2ee762ea11b3 1107 skipCommentTokens(token);
tgw 0:2ee762ea11b3 1108 bool successful = true;
tgw 0:2ee762ea11b3 1109
tgw 0:2ee762ea11b3 1110 if (collectComments_ && !commentsBefore_.empty()) {
tgw 0:2ee762ea11b3 1111 currentValue().setComment(commentsBefore_, commentBefore);
tgw 0:2ee762ea11b3 1112 commentsBefore_.clear();
tgw 0:2ee762ea11b3 1113 }
tgw 0:2ee762ea11b3 1114
tgw 0:2ee762ea11b3 1115 switch (token.type_) {
tgw 0:2ee762ea11b3 1116 case tokenObjectBegin:
tgw 0:2ee762ea11b3 1117 successful = readObject(token);
tgw 0:2ee762ea11b3 1118 currentValue().setOffsetLimit(current_ - begin_);
tgw 0:2ee762ea11b3 1119 break;
tgw 0:2ee762ea11b3 1120 case tokenArrayBegin:
tgw 0:2ee762ea11b3 1121 successful = readArray(token);
tgw 0:2ee762ea11b3 1122 currentValue().setOffsetLimit(current_ - begin_);
tgw 0:2ee762ea11b3 1123 break;
tgw 0:2ee762ea11b3 1124 case tokenNumber:
tgw 0:2ee762ea11b3 1125 successful = decodeNumber(token);
tgw 0:2ee762ea11b3 1126 break;
tgw 0:2ee762ea11b3 1127 case tokenString:
tgw 0:2ee762ea11b3 1128 successful = decodeString(token);
tgw 0:2ee762ea11b3 1129 break;
tgw 0:2ee762ea11b3 1130 case tokenTrue:
tgw 0:2ee762ea11b3 1131 {
tgw 0:2ee762ea11b3 1132 Value v(true);
tgw 0:2ee762ea11b3 1133 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1134 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1135 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1136 }
tgw 0:2ee762ea11b3 1137 break;
tgw 0:2ee762ea11b3 1138 case tokenFalse:
tgw 0:2ee762ea11b3 1139 {
tgw 0:2ee762ea11b3 1140 Value v(false);
tgw 0:2ee762ea11b3 1141 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1142 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1143 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1144 }
tgw 0:2ee762ea11b3 1145 break;
tgw 0:2ee762ea11b3 1146 case tokenNull:
tgw 0:2ee762ea11b3 1147 {
tgw 0:2ee762ea11b3 1148 Value v;
tgw 0:2ee762ea11b3 1149 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1150 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1151 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1152 }
tgw 0:2ee762ea11b3 1153 break;
tgw 0:2ee762ea11b3 1154 case tokenNaN:
tgw 0:2ee762ea11b3 1155 {
tgw 0:2ee762ea11b3 1156 Value v(std::numeric_limits<double>::quiet_NaN());
tgw 0:2ee762ea11b3 1157 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1158 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1159 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1160 }
tgw 0:2ee762ea11b3 1161 break;
tgw 0:2ee762ea11b3 1162 case tokenPosInf:
tgw 0:2ee762ea11b3 1163 {
tgw 0:2ee762ea11b3 1164 Value v(std::numeric_limits<double>::infinity());
tgw 0:2ee762ea11b3 1165 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1166 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1167 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1168 }
tgw 0:2ee762ea11b3 1169 break;
tgw 0:2ee762ea11b3 1170 case tokenNegInf:
tgw 0:2ee762ea11b3 1171 {
tgw 0:2ee762ea11b3 1172 Value v(-std::numeric_limits<double>::infinity());
tgw 0:2ee762ea11b3 1173 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1174 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1175 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1176 }
tgw 0:2ee762ea11b3 1177 break;
tgw 0:2ee762ea11b3 1178 case tokenArraySeparator:
tgw 0:2ee762ea11b3 1179 case tokenObjectEnd:
tgw 0:2ee762ea11b3 1180 case tokenArrayEnd:
tgw 0:2ee762ea11b3 1181 if (features_.allowDroppedNullPlaceholders_) {
tgw 0:2ee762ea11b3 1182 // "Un-read" the current token and mark the current value as a null
tgw 0:2ee762ea11b3 1183 // token.
tgw 0:2ee762ea11b3 1184 current_--;
tgw 0:2ee762ea11b3 1185 Value v;
tgw 0:2ee762ea11b3 1186 currentValue().swapPayload(v);
tgw 0:2ee762ea11b3 1187 currentValue().setOffsetStart(current_ - begin_ - 1);
tgw 0:2ee762ea11b3 1188 currentValue().setOffsetLimit(current_ - begin_);
tgw 0:2ee762ea11b3 1189 break;
tgw 0:2ee762ea11b3 1190 } // else, fall through ...
tgw 0:2ee762ea11b3 1191 default:
tgw 0:2ee762ea11b3 1192 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1193 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1194 return addError("Syntax error: value, object or array expected.", token);
tgw 0:2ee762ea11b3 1195 }
tgw 0:2ee762ea11b3 1196
tgw 0:2ee762ea11b3 1197 if (collectComments_) {
tgw 0:2ee762ea11b3 1198 lastValueEnd_ = current_;
tgw 0:2ee762ea11b3 1199 lastValue_ = &currentValue();
tgw 0:2ee762ea11b3 1200 }
tgw 0:2ee762ea11b3 1201
tgw 0:2ee762ea11b3 1202 return successful;
tgw 0:2ee762ea11b3 1203 }
tgw 0:2ee762ea11b3 1204
tgw 0:2ee762ea11b3 1205 void OurReader::skipCommentTokens(Token& token) {
tgw 0:2ee762ea11b3 1206 if (features_.allowComments_) {
tgw 0:2ee762ea11b3 1207 do {
tgw 0:2ee762ea11b3 1208 readToken(token);
tgw 0:2ee762ea11b3 1209 } while (token.type_ == tokenComment);
tgw 0:2ee762ea11b3 1210 } else {
tgw 0:2ee762ea11b3 1211 readToken(token);
tgw 0:2ee762ea11b3 1212 }
tgw 0:2ee762ea11b3 1213 }
tgw 0:2ee762ea11b3 1214
tgw 0:2ee762ea11b3 1215 bool OurReader::readToken(Token& token) {
tgw 0:2ee762ea11b3 1216 skipSpaces();
tgw 0:2ee762ea11b3 1217 token.start_ = current_;
tgw 0:2ee762ea11b3 1218 Char c = getNextChar();
tgw 0:2ee762ea11b3 1219 bool ok = true;
tgw 0:2ee762ea11b3 1220 switch (c) {
tgw 0:2ee762ea11b3 1221 case '{':
tgw 0:2ee762ea11b3 1222 token.type_ = tokenObjectBegin;
tgw 0:2ee762ea11b3 1223 break;
tgw 0:2ee762ea11b3 1224 case '}':
tgw 0:2ee762ea11b3 1225 token.type_ = tokenObjectEnd;
tgw 0:2ee762ea11b3 1226 break;
tgw 0:2ee762ea11b3 1227 case '[':
tgw 0:2ee762ea11b3 1228 token.type_ = tokenArrayBegin;
tgw 0:2ee762ea11b3 1229 break;
tgw 0:2ee762ea11b3 1230 case ']':
tgw 0:2ee762ea11b3 1231 token.type_ = tokenArrayEnd;
tgw 0:2ee762ea11b3 1232 break;
tgw 0:2ee762ea11b3 1233 case '"':
tgw 0:2ee762ea11b3 1234 token.type_ = tokenString;
tgw 0:2ee762ea11b3 1235 ok = readString();
tgw 0:2ee762ea11b3 1236 break;
tgw 0:2ee762ea11b3 1237 case '\'':
tgw 0:2ee762ea11b3 1238 if (features_.allowSingleQuotes_) {
tgw 0:2ee762ea11b3 1239 token.type_ = tokenString;
tgw 0:2ee762ea11b3 1240 ok = readStringSingleQuote();
tgw 0:2ee762ea11b3 1241 break;
tgw 0:2ee762ea11b3 1242 } // else fall through
tgw 0:2ee762ea11b3 1243 case '/':
tgw 0:2ee762ea11b3 1244 token.type_ = tokenComment;
tgw 0:2ee762ea11b3 1245 ok = readComment();
tgw 0:2ee762ea11b3 1246 break;
tgw 0:2ee762ea11b3 1247 case '0':
tgw 0:2ee762ea11b3 1248 case '1':
tgw 0:2ee762ea11b3 1249 case '2':
tgw 0:2ee762ea11b3 1250 case '3':
tgw 0:2ee762ea11b3 1251 case '4':
tgw 0:2ee762ea11b3 1252 case '5':
tgw 0:2ee762ea11b3 1253 case '6':
tgw 0:2ee762ea11b3 1254 case '7':
tgw 0:2ee762ea11b3 1255 case '8':
tgw 0:2ee762ea11b3 1256 case '9':
tgw 0:2ee762ea11b3 1257 token.type_ = tokenNumber;
tgw 0:2ee762ea11b3 1258 readNumber(false);
tgw 0:2ee762ea11b3 1259 break;
tgw 0:2ee762ea11b3 1260 case '-':
tgw 0:2ee762ea11b3 1261 if (readNumber(true)) {
tgw 0:2ee762ea11b3 1262 token.type_ = tokenNumber;
tgw 0:2ee762ea11b3 1263 } else {
tgw 0:2ee762ea11b3 1264 token.type_ = tokenNegInf;
tgw 0:2ee762ea11b3 1265 ok = features_.allowSpecialFloats_ && match("nfinity", 7);
tgw 0:2ee762ea11b3 1266 }
tgw 0:2ee762ea11b3 1267 break;
tgw 0:2ee762ea11b3 1268 case 't':
tgw 0:2ee762ea11b3 1269 token.type_ = tokenTrue;
tgw 0:2ee762ea11b3 1270 ok = match("rue", 3);
tgw 0:2ee762ea11b3 1271 break;
tgw 0:2ee762ea11b3 1272 case 'f':
tgw 0:2ee762ea11b3 1273 token.type_ = tokenFalse;
tgw 0:2ee762ea11b3 1274 ok = match("alse", 4);
tgw 0:2ee762ea11b3 1275 break;
tgw 0:2ee762ea11b3 1276 case 'n':
tgw 0:2ee762ea11b3 1277 token.type_ = tokenNull;
tgw 0:2ee762ea11b3 1278 ok = match("ull", 3);
tgw 0:2ee762ea11b3 1279 break;
tgw 0:2ee762ea11b3 1280 case 'N':
tgw 0:2ee762ea11b3 1281 if (features_.allowSpecialFloats_) {
tgw 0:2ee762ea11b3 1282 token.type_ = tokenNaN;
tgw 0:2ee762ea11b3 1283 ok = match("aN", 2);
tgw 0:2ee762ea11b3 1284 } else {
tgw 0:2ee762ea11b3 1285 ok = false;
tgw 0:2ee762ea11b3 1286 }
tgw 0:2ee762ea11b3 1287 break;
tgw 0:2ee762ea11b3 1288 case 'I':
tgw 0:2ee762ea11b3 1289 if (features_.allowSpecialFloats_) {
tgw 0:2ee762ea11b3 1290 token.type_ = tokenPosInf;
tgw 0:2ee762ea11b3 1291 ok = match("nfinity", 7);
tgw 0:2ee762ea11b3 1292 } else {
tgw 0:2ee762ea11b3 1293 ok = false;
tgw 0:2ee762ea11b3 1294 }
tgw 0:2ee762ea11b3 1295 break;
tgw 0:2ee762ea11b3 1296 case ',':
tgw 0:2ee762ea11b3 1297 token.type_ = tokenArraySeparator;
tgw 0:2ee762ea11b3 1298 break;
tgw 0:2ee762ea11b3 1299 case ':':
tgw 0:2ee762ea11b3 1300 token.type_ = tokenMemberSeparator;
tgw 0:2ee762ea11b3 1301 break;
tgw 0:2ee762ea11b3 1302 case 0:
tgw 0:2ee762ea11b3 1303 token.type_ = tokenEndOfStream;
tgw 0:2ee762ea11b3 1304 break;
tgw 0:2ee762ea11b3 1305 default:
tgw 0:2ee762ea11b3 1306 ok = false;
tgw 0:2ee762ea11b3 1307 break;
tgw 0:2ee762ea11b3 1308 }
tgw 0:2ee762ea11b3 1309 if (!ok)
tgw 0:2ee762ea11b3 1310 token.type_ = tokenError;
tgw 0:2ee762ea11b3 1311 token.end_ = current_;
tgw 0:2ee762ea11b3 1312 return true;
tgw 0:2ee762ea11b3 1313 }
tgw 0:2ee762ea11b3 1314
tgw 0:2ee762ea11b3 1315 void OurReader::skipSpaces() {
tgw 0:2ee762ea11b3 1316 while (current_ != end_) {
tgw 0:2ee762ea11b3 1317 Char c = *current_;
tgw 0:2ee762ea11b3 1318 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
tgw 0:2ee762ea11b3 1319 ++current_;
tgw 0:2ee762ea11b3 1320 else
tgw 0:2ee762ea11b3 1321 break;
tgw 0:2ee762ea11b3 1322 }
tgw 0:2ee762ea11b3 1323 }
tgw 0:2ee762ea11b3 1324
tgw 0:2ee762ea11b3 1325 bool OurReader::match(Location pattern, int patternLength) {
tgw 0:2ee762ea11b3 1326 if (end_ - current_ < patternLength)
tgw 0:2ee762ea11b3 1327 return false;
tgw 0:2ee762ea11b3 1328 int index = patternLength;
tgw 0:2ee762ea11b3 1329 while (index--)
tgw 0:2ee762ea11b3 1330 if (current_[index] != pattern[index])
tgw 0:2ee762ea11b3 1331 return false;
tgw 0:2ee762ea11b3 1332 current_ += patternLength;
tgw 0:2ee762ea11b3 1333 return true;
tgw 0:2ee762ea11b3 1334 }
tgw 0:2ee762ea11b3 1335
tgw 0:2ee762ea11b3 1336 bool OurReader::readComment() {
tgw 0:2ee762ea11b3 1337 Location commentBegin = current_ - 1;
tgw 0:2ee762ea11b3 1338 Char c = getNextChar();
tgw 0:2ee762ea11b3 1339 bool successful = false;
tgw 0:2ee762ea11b3 1340 if (c == '*')
tgw 0:2ee762ea11b3 1341 successful = readCStyleComment();
tgw 0:2ee762ea11b3 1342 else if (c == '/')
tgw 0:2ee762ea11b3 1343 successful = readCppStyleComment();
tgw 0:2ee762ea11b3 1344 if (!successful)
tgw 0:2ee762ea11b3 1345 return false;
tgw 0:2ee762ea11b3 1346
tgw 0:2ee762ea11b3 1347 if (collectComments_) {
tgw 0:2ee762ea11b3 1348 CommentPlacement placement = commentBefore;
tgw 0:2ee762ea11b3 1349 if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
tgw 0:2ee762ea11b3 1350 if (c != '*' || !containsNewLine(commentBegin, current_))
tgw 0:2ee762ea11b3 1351 placement = commentAfterOnSameLine;
tgw 0:2ee762ea11b3 1352 }
tgw 0:2ee762ea11b3 1353
tgw 0:2ee762ea11b3 1354 addComment(commentBegin, current_, placement);
tgw 0:2ee762ea11b3 1355 }
tgw 0:2ee762ea11b3 1356 return true;
tgw 0:2ee762ea11b3 1357 }
tgw 0:2ee762ea11b3 1358
tgw 0:2ee762ea11b3 1359 JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) {
tgw 0:2ee762ea11b3 1360 JSONCPP_STRING normalized;
tgw 0:2ee762ea11b3 1361 normalized.reserve(static_cast<size_t>(end - begin));
tgw 0:2ee762ea11b3 1362 OurReader::Location current = begin;
tgw 0:2ee762ea11b3 1363 while (current != end) {
tgw 0:2ee762ea11b3 1364 char c = *current++;
tgw 0:2ee762ea11b3 1365 if (c == '\r') {
tgw 0:2ee762ea11b3 1366 if (current != end && *current == '\n')
tgw 0:2ee762ea11b3 1367 // convert dos EOL
tgw 0:2ee762ea11b3 1368 ++current;
tgw 0:2ee762ea11b3 1369 // convert Mac EOL
tgw 0:2ee762ea11b3 1370 normalized += '\n';
tgw 0:2ee762ea11b3 1371 } else {
tgw 0:2ee762ea11b3 1372 normalized += c;
tgw 0:2ee762ea11b3 1373 }
tgw 0:2ee762ea11b3 1374 }
tgw 0:2ee762ea11b3 1375 return normalized;
tgw 0:2ee762ea11b3 1376 }
tgw 0:2ee762ea11b3 1377
tgw 0:2ee762ea11b3 1378 void
tgw 0:2ee762ea11b3 1379 OurReader::addComment(Location begin, Location end, CommentPlacement placement) {
tgw 0:2ee762ea11b3 1380 assert(collectComments_);
tgw 0:2ee762ea11b3 1381 const JSONCPP_STRING& normalized = normalizeEOL(begin, end);
tgw 0:2ee762ea11b3 1382 if (placement == commentAfterOnSameLine) {
tgw 0:2ee762ea11b3 1383 assert(lastValue_ != 0);
tgw 0:2ee762ea11b3 1384 lastValue_->setComment(normalized, placement);
tgw 0:2ee762ea11b3 1385 } else {
tgw 0:2ee762ea11b3 1386 commentsBefore_ += normalized;
tgw 0:2ee762ea11b3 1387 }
tgw 0:2ee762ea11b3 1388 }
tgw 0:2ee762ea11b3 1389
tgw 0:2ee762ea11b3 1390 bool OurReader::readCStyleComment() {
tgw 0:2ee762ea11b3 1391 while ((current_ + 1) < end_) {
tgw 0:2ee762ea11b3 1392 Char c = getNextChar();
tgw 0:2ee762ea11b3 1393 if (c == '*' && *current_ == '/')
tgw 0:2ee762ea11b3 1394 break;
tgw 0:2ee762ea11b3 1395 }
tgw 0:2ee762ea11b3 1396 return getNextChar() == '/';
tgw 0:2ee762ea11b3 1397 }
tgw 0:2ee762ea11b3 1398
tgw 0:2ee762ea11b3 1399 bool OurReader::readCppStyleComment() {
tgw 0:2ee762ea11b3 1400 while (current_ != end_) {
tgw 0:2ee762ea11b3 1401 Char c = getNextChar();
tgw 0:2ee762ea11b3 1402 if (c == '\n')
tgw 0:2ee762ea11b3 1403 break;
tgw 0:2ee762ea11b3 1404 if (c == '\r') {
tgw 0:2ee762ea11b3 1405 // Consume DOS EOL. It will be normalized in addComment.
tgw 0:2ee762ea11b3 1406 if (current_ != end_ && *current_ == '\n')
tgw 0:2ee762ea11b3 1407 getNextChar();
tgw 0:2ee762ea11b3 1408 // Break on Moc OS 9 EOL.
tgw 0:2ee762ea11b3 1409 break;
tgw 0:2ee762ea11b3 1410 }
tgw 0:2ee762ea11b3 1411 }
tgw 0:2ee762ea11b3 1412 return true;
tgw 0:2ee762ea11b3 1413 }
tgw 0:2ee762ea11b3 1414
tgw 0:2ee762ea11b3 1415 bool OurReader::readNumber(bool checkInf) {
tgw 0:2ee762ea11b3 1416 const char *p = current_;
tgw 0:2ee762ea11b3 1417 if (checkInf && p != end_ && *p == 'I') {
tgw 0:2ee762ea11b3 1418 current_ = ++p;
tgw 0:2ee762ea11b3 1419 return false;
tgw 0:2ee762ea11b3 1420 }
tgw 0:2ee762ea11b3 1421 char c = '0'; // stopgap for already consumed character
tgw 0:2ee762ea11b3 1422 // integral part
tgw 0:2ee762ea11b3 1423 while (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 1424 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 1425 // fractional part
tgw 0:2ee762ea11b3 1426 if (c == '.') {
tgw 0:2ee762ea11b3 1427 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 1428 while (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 1429 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 1430 }
tgw 0:2ee762ea11b3 1431 // exponential part
tgw 0:2ee762ea11b3 1432 if (c == 'e' || c == 'E') {
tgw 0:2ee762ea11b3 1433 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 1434 if (c == '+' || c == '-')
tgw 0:2ee762ea11b3 1435 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 1436 while (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 1437 c = (current_ = p) < end_ ? *p++ : '\0';
tgw 0:2ee762ea11b3 1438 }
tgw 0:2ee762ea11b3 1439 return true;
tgw 0:2ee762ea11b3 1440 }
tgw 0:2ee762ea11b3 1441 bool OurReader::readString() {
tgw 0:2ee762ea11b3 1442 Char c = 0;
tgw 0:2ee762ea11b3 1443 while (current_ != end_) {
tgw 0:2ee762ea11b3 1444 c = getNextChar();
tgw 0:2ee762ea11b3 1445 if (c == '\\')
tgw 0:2ee762ea11b3 1446 getNextChar();
tgw 0:2ee762ea11b3 1447 else if (c == '"')
tgw 0:2ee762ea11b3 1448 break;
tgw 0:2ee762ea11b3 1449 }
tgw 0:2ee762ea11b3 1450 return c == '"';
tgw 0:2ee762ea11b3 1451 }
tgw 0:2ee762ea11b3 1452
tgw 0:2ee762ea11b3 1453
tgw 0:2ee762ea11b3 1454 bool OurReader::readStringSingleQuote() {
tgw 0:2ee762ea11b3 1455 Char c = 0;
tgw 0:2ee762ea11b3 1456 while (current_ != end_) {
tgw 0:2ee762ea11b3 1457 c = getNextChar();
tgw 0:2ee762ea11b3 1458 if (c == '\\')
tgw 0:2ee762ea11b3 1459 getNextChar();
tgw 0:2ee762ea11b3 1460 else if (c == '\'')
tgw 0:2ee762ea11b3 1461 break;
tgw 0:2ee762ea11b3 1462 }
tgw 0:2ee762ea11b3 1463 return c == '\'';
tgw 0:2ee762ea11b3 1464 }
tgw 0:2ee762ea11b3 1465
tgw 0:2ee762ea11b3 1466 bool OurReader::readObject(Token& tokenStart) {
tgw 0:2ee762ea11b3 1467 Token tokenName;
tgw 0:2ee762ea11b3 1468 JSONCPP_STRING name;
tgw 0:2ee762ea11b3 1469 Value init(objectValue);
tgw 0:2ee762ea11b3 1470 currentValue().swapPayload(init);
tgw 0:2ee762ea11b3 1471 currentValue().setOffsetStart(tokenStart.start_ - begin_);
tgw 0:2ee762ea11b3 1472 while (readToken(tokenName)) {
tgw 0:2ee762ea11b3 1473 bool initialTokenOk = true;
tgw 0:2ee762ea11b3 1474 while (tokenName.type_ == tokenComment && initialTokenOk)
tgw 0:2ee762ea11b3 1475 initialTokenOk = readToken(tokenName);
tgw 0:2ee762ea11b3 1476 if (!initialTokenOk)
tgw 0:2ee762ea11b3 1477 break;
tgw 0:2ee762ea11b3 1478 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
tgw 0:2ee762ea11b3 1479 return true;
tgw 0:2ee762ea11b3 1480 name.clear();
tgw 0:2ee762ea11b3 1481 if (tokenName.type_ == tokenString) {
tgw 0:2ee762ea11b3 1482 if (!decodeString(tokenName, name))
tgw 0:2ee762ea11b3 1483 return recoverFromError(tokenObjectEnd);
tgw 0:2ee762ea11b3 1484 } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
tgw 0:2ee762ea11b3 1485 Value numberName;
tgw 0:2ee762ea11b3 1486 if (!decodeNumber(tokenName, numberName))
tgw 0:2ee762ea11b3 1487 return recoverFromError(tokenObjectEnd);
tgw 0:2ee762ea11b3 1488 name = numberName.asString();
tgw 0:2ee762ea11b3 1489 } else {
tgw 0:2ee762ea11b3 1490 break;
tgw 0:2ee762ea11b3 1491 }
tgw 0:2ee762ea11b3 1492
tgw 0:2ee762ea11b3 1493 Token colon;
tgw 0:2ee762ea11b3 1494 if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
tgw 0:2ee762ea11b3 1495 return addErrorAndRecover(
tgw 0:2ee762ea11b3 1496 "Missing ':' after object member name", colon, tokenObjectEnd);
tgw 0:2ee762ea11b3 1497 }
tgw 0:2ee762ea11b3 1498 if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30");
tgw 0:2ee762ea11b3 1499 if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
tgw 0:2ee762ea11b3 1500 JSONCPP_STRING msg = "Duplicate key: '" + name + "'";
tgw 0:2ee762ea11b3 1501 return addErrorAndRecover(
tgw 0:2ee762ea11b3 1502 msg, tokenName, tokenObjectEnd);
tgw 0:2ee762ea11b3 1503 }
tgw 0:2ee762ea11b3 1504 Value& value = currentValue()[name];
tgw 0:2ee762ea11b3 1505 nodes_.push(&value);
tgw 0:2ee762ea11b3 1506 bool ok = readValue();
tgw 0:2ee762ea11b3 1507 nodes_.pop();
tgw 0:2ee762ea11b3 1508 if (!ok) // error already set
tgw 0:2ee762ea11b3 1509 return recoverFromError(tokenObjectEnd);
tgw 0:2ee762ea11b3 1510
tgw 0:2ee762ea11b3 1511 Token comma;
tgw 0:2ee762ea11b3 1512 if (!readToken(comma) ||
tgw 0:2ee762ea11b3 1513 (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
tgw 0:2ee762ea11b3 1514 comma.type_ != tokenComment)) {
tgw 0:2ee762ea11b3 1515 return addErrorAndRecover(
tgw 0:2ee762ea11b3 1516 "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
tgw 0:2ee762ea11b3 1517 }
tgw 0:2ee762ea11b3 1518 bool finalizeTokenOk = true;
tgw 0:2ee762ea11b3 1519 while (comma.type_ == tokenComment && finalizeTokenOk)
tgw 0:2ee762ea11b3 1520 finalizeTokenOk = readToken(comma);
tgw 0:2ee762ea11b3 1521 if (comma.type_ == tokenObjectEnd)
tgw 0:2ee762ea11b3 1522 return true;
tgw 0:2ee762ea11b3 1523 }
tgw 0:2ee762ea11b3 1524 return addErrorAndRecover(
tgw 0:2ee762ea11b3 1525 "Missing '}' or object member name", tokenName, tokenObjectEnd);
tgw 0:2ee762ea11b3 1526 }
tgw 0:2ee762ea11b3 1527
tgw 0:2ee762ea11b3 1528 bool OurReader::readArray(Token& tokenStart) {
tgw 0:2ee762ea11b3 1529 Value init(arrayValue);
tgw 0:2ee762ea11b3 1530 currentValue().swapPayload(init);
tgw 0:2ee762ea11b3 1531 currentValue().setOffsetStart(tokenStart.start_ - begin_);
tgw 0:2ee762ea11b3 1532 skipSpaces();
tgw 0:2ee762ea11b3 1533 if (current_ != end_ && *current_ == ']') // empty array
tgw 0:2ee762ea11b3 1534 {
tgw 0:2ee762ea11b3 1535 Token endArray;
tgw 0:2ee762ea11b3 1536 readToken(endArray);
tgw 0:2ee762ea11b3 1537 return true;
tgw 0:2ee762ea11b3 1538 }
tgw 0:2ee762ea11b3 1539 int index = 0;
tgw 0:2ee762ea11b3 1540 for (;;) {
tgw 0:2ee762ea11b3 1541 Value& value = currentValue()[index++];
tgw 0:2ee762ea11b3 1542 nodes_.push(&value);
tgw 0:2ee762ea11b3 1543 bool ok = readValue();
tgw 0:2ee762ea11b3 1544 nodes_.pop();
tgw 0:2ee762ea11b3 1545 if (!ok) // error already set
tgw 0:2ee762ea11b3 1546 return recoverFromError(tokenArrayEnd);
tgw 0:2ee762ea11b3 1547
tgw 0:2ee762ea11b3 1548 Token token;
tgw 0:2ee762ea11b3 1549 // Accept Comment after last item in the array.
tgw 0:2ee762ea11b3 1550 ok = readToken(token);
tgw 0:2ee762ea11b3 1551 while (token.type_ == tokenComment && ok) {
tgw 0:2ee762ea11b3 1552 ok = readToken(token);
tgw 0:2ee762ea11b3 1553 }
tgw 0:2ee762ea11b3 1554 bool badTokenType =
tgw 0:2ee762ea11b3 1555 (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
tgw 0:2ee762ea11b3 1556 if (!ok || badTokenType) {
tgw 0:2ee762ea11b3 1557 return addErrorAndRecover(
tgw 0:2ee762ea11b3 1558 "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
tgw 0:2ee762ea11b3 1559 }
tgw 0:2ee762ea11b3 1560 if (token.type_ == tokenArrayEnd)
tgw 0:2ee762ea11b3 1561 break;
tgw 0:2ee762ea11b3 1562 }
tgw 0:2ee762ea11b3 1563 return true;
tgw 0:2ee762ea11b3 1564 }
tgw 0:2ee762ea11b3 1565
tgw 0:2ee762ea11b3 1566 bool OurReader::decodeNumber(Token& token) {
tgw 0:2ee762ea11b3 1567 Value decoded;
tgw 0:2ee762ea11b3 1568 if (!decodeNumber(token, decoded))
tgw 0:2ee762ea11b3 1569 return false;
tgw 0:2ee762ea11b3 1570 currentValue().swapPayload(decoded);
tgw 0:2ee762ea11b3 1571 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1572 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1573 return true;
tgw 0:2ee762ea11b3 1574 }
tgw 0:2ee762ea11b3 1575
tgw 0:2ee762ea11b3 1576 bool OurReader::decodeNumber(Token& token, Value& decoded) {
tgw 0:2ee762ea11b3 1577 // Attempts to parse the number as an integer. If the number is
tgw 0:2ee762ea11b3 1578 // larger than the maximum supported value of an integer then
tgw 0:2ee762ea11b3 1579 // we decode the number as a double.
tgw 0:2ee762ea11b3 1580 Location current = token.start_;
tgw 0:2ee762ea11b3 1581 bool isNegative = *current == '-';
tgw 0:2ee762ea11b3 1582 if (isNegative)
tgw 0:2ee762ea11b3 1583 ++current;
tgw 0:2ee762ea11b3 1584 // TODO: Help the compiler do the div and mod at compile time or get rid of them.
tgw 0:2ee762ea11b3 1585 Value::LargestUInt maxIntegerValue =
tgw 0:2ee762ea11b3 1586 isNegative ? Value::LargestUInt(-Value::minLargestInt)
tgw 0:2ee762ea11b3 1587 : Value::maxLargestUInt;
tgw 0:2ee762ea11b3 1588 Value::LargestUInt threshold = maxIntegerValue / 10;
tgw 0:2ee762ea11b3 1589 Value::LargestUInt value = 0;
tgw 0:2ee762ea11b3 1590 while (current < token.end_) {
tgw 0:2ee762ea11b3 1591 Char c = *current++;
tgw 0:2ee762ea11b3 1592 if (c < '0' || c > '9')
tgw 0:2ee762ea11b3 1593 return decodeDouble(token, decoded);
tgw 0:2ee762ea11b3 1594 Value::UInt digit(static_cast<Value::UInt>(c - '0'));
tgw 0:2ee762ea11b3 1595 if (value >= threshold) {
tgw 0:2ee762ea11b3 1596 // We've hit or exceeded the max value divided by 10 (rounded down). If
tgw 0:2ee762ea11b3 1597 // a) we've only just touched the limit, b) this is the last digit, and
tgw 0:2ee762ea11b3 1598 // c) it's small enough to fit in that rounding delta, we're okay.
tgw 0:2ee762ea11b3 1599 // Otherwise treat this number as a double to avoid overflow.
tgw 0:2ee762ea11b3 1600 if (value > threshold || current != token.end_ ||
tgw 0:2ee762ea11b3 1601 digit > maxIntegerValue % 10) {
tgw 0:2ee762ea11b3 1602 return decodeDouble(token, decoded);
tgw 0:2ee762ea11b3 1603 }
tgw 0:2ee762ea11b3 1604 }
tgw 0:2ee762ea11b3 1605 value = value * 10 + digit;
tgw 0:2ee762ea11b3 1606 }
tgw 0:2ee762ea11b3 1607 if (isNegative)
tgw 0:2ee762ea11b3 1608 decoded = -Value::LargestInt(value);
tgw 0:2ee762ea11b3 1609 else if (value <= Value::LargestUInt(Value::maxInt))
tgw 0:2ee762ea11b3 1610 decoded = Value::LargestInt(value);
tgw 0:2ee762ea11b3 1611 else
tgw 0:2ee762ea11b3 1612 decoded = value;
tgw 0:2ee762ea11b3 1613 return true;
tgw 0:2ee762ea11b3 1614 }
tgw 0:2ee762ea11b3 1615
tgw 0:2ee762ea11b3 1616 bool OurReader::decodeDouble(Token& token) {
tgw 0:2ee762ea11b3 1617 Value decoded;
tgw 0:2ee762ea11b3 1618 if (!decodeDouble(token, decoded))
tgw 0:2ee762ea11b3 1619 return false;
tgw 0:2ee762ea11b3 1620 currentValue().swapPayload(decoded);
tgw 0:2ee762ea11b3 1621 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1622 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1623 return true;
tgw 0:2ee762ea11b3 1624 }
tgw 0:2ee762ea11b3 1625
tgw 0:2ee762ea11b3 1626 bool OurReader::decodeDouble(Token& token, Value& decoded) {
tgw 0:2ee762ea11b3 1627 double value = 0;
tgw 0:2ee762ea11b3 1628 const int bufferSize = 32;
tgw 0:2ee762ea11b3 1629 int count;
tgw 0:2ee762ea11b3 1630 ptrdiff_t const length = token.end_ - token.start_;
tgw 0:2ee762ea11b3 1631
tgw 0:2ee762ea11b3 1632 // Sanity check to avoid buffer overflow exploits.
tgw 0:2ee762ea11b3 1633 if (length < 0) {
tgw 0:2ee762ea11b3 1634 return addError("Unable to parse token length", token);
tgw 0:2ee762ea11b3 1635 }
tgw 0:2ee762ea11b3 1636 size_t const ulength = static_cast<size_t>(length);
tgw 0:2ee762ea11b3 1637
tgw 0:2ee762ea11b3 1638 // Avoid using a string constant for the format control string given to
tgw 0:2ee762ea11b3 1639 // sscanf, as this can cause hard to debug crashes on OS X. See here for more
tgw 0:2ee762ea11b3 1640 // info:
tgw 0:2ee762ea11b3 1641 //
tgw 0:2ee762ea11b3 1642 // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
tgw 0:2ee762ea11b3 1643 char format[] = "%lf";
tgw 0:2ee762ea11b3 1644
tgw 0:2ee762ea11b3 1645 if (length <= bufferSize) {
tgw 0:2ee762ea11b3 1646 Char buffer[bufferSize + 1];
tgw 0:2ee762ea11b3 1647 memcpy(buffer, token.start_, ulength);
tgw 0:2ee762ea11b3 1648 buffer[length] = 0;
tgw 0:2ee762ea11b3 1649 fixNumericLocaleInput(buffer, buffer + length);
tgw 0:2ee762ea11b3 1650 count = sscanf(buffer, format, &value);
tgw 0:2ee762ea11b3 1651 } else {
tgw 0:2ee762ea11b3 1652 JSONCPP_STRING buffer(token.start_, token.end_);
tgw 0:2ee762ea11b3 1653 count = sscanf(buffer.c_str(), format, &value);
tgw 0:2ee762ea11b3 1654 }
tgw 0:2ee762ea11b3 1655
tgw 0:2ee762ea11b3 1656 if (count != 1)
tgw 0:2ee762ea11b3 1657 return addError("'" + JSONCPP_STRING(token.start_, token.end_) +
tgw 0:2ee762ea11b3 1658 "' is not a number.",
tgw 0:2ee762ea11b3 1659 token);
tgw 0:2ee762ea11b3 1660 decoded = value;
tgw 0:2ee762ea11b3 1661 return true;
tgw 0:2ee762ea11b3 1662 }
tgw 0:2ee762ea11b3 1663
tgw 0:2ee762ea11b3 1664 bool OurReader::decodeString(Token& token) {
tgw 0:2ee762ea11b3 1665 JSONCPP_STRING decoded_string;
tgw 0:2ee762ea11b3 1666 if (!decodeString(token, decoded_string))
tgw 0:2ee762ea11b3 1667 return false;
tgw 0:2ee762ea11b3 1668 Value decoded(decoded_string);
tgw 0:2ee762ea11b3 1669 currentValue().swapPayload(decoded);
tgw 0:2ee762ea11b3 1670 currentValue().setOffsetStart(token.start_ - begin_);
tgw 0:2ee762ea11b3 1671 currentValue().setOffsetLimit(token.end_ - begin_);
tgw 0:2ee762ea11b3 1672 return true;
tgw 0:2ee762ea11b3 1673 }
tgw 0:2ee762ea11b3 1674
tgw 0:2ee762ea11b3 1675 bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) {
tgw 0:2ee762ea11b3 1676 decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
tgw 0:2ee762ea11b3 1677 Location current = token.start_ + 1; // skip '"'
tgw 0:2ee762ea11b3 1678 Location end = token.end_ - 1; // do not include '"'
tgw 0:2ee762ea11b3 1679 while (current != end) {
tgw 0:2ee762ea11b3 1680 Char c = *current++;
tgw 0:2ee762ea11b3 1681 if (c == '"')
tgw 0:2ee762ea11b3 1682 break;
tgw 0:2ee762ea11b3 1683 else if (c == '\\') {
tgw 0:2ee762ea11b3 1684 if (current == end)
tgw 0:2ee762ea11b3 1685 return addError("Empty escape sequence in string", token, current);
tgw 0:2ee762ea11b3 1686 Char escape = *current++;
tgw 0:2ee762ea11b3 1687 switch (escape) {
tgw 0:2ee762ea11b3 1688 case '"':
tgw 0:2ee762ea11b3 1689 decoded += '"';
tgw 0:2ee762ea11b3 1690 break;
tgw 0:2ee762ea11b3 1691 case '/':
tgw 0:2ee762ea11b3 1692 decoded += '/';
tgw 0:2ee762ea11b3 1693 break;
tgw 0:2ee762ea11b3 1694 case '\\':
tgw 0:2ee762ea11b3 1695 decoded += '\\';
tgw 0:2ee762ea11b3 1696 break;
tgw 0:2ee762ea11b3 1697 case 'b':
tgw 0:2ee762ea11b3 1698 decoded += '\b';
tgw 0:2ee762ea11b3 1699 break;
tgw 0:2ee762ea11b3 1700 case 'f':
tgw 0:2ee762ea11b3 1701 decoded += '\f';
tgw 0:2ee762ea11b3 1702 break;
tgw 0:2ee762ea11b3 1703 case 'n':
tgw 0:2ee762ea11b3 1704 decoded += '\n';
tgw 0:2ee762ea11b3 1705 break;
tgw 0:2ee762ea11b3 1706 case 'r':
tgw 0:2ee762ea11b3 1707 decoded += '\r';
tgw 0:2ee762ea11b3 1708 break;
tgw 0:2ee762ea11b3 1709 case 't':
tgw 0:2ee762ea11b3 1710 decoded += '\t';
tgw 0:2ee762ea11b3 1711 break;
tgw 0:2ee762ea11b3 1712 case 'u': {
tgw 0:2ee762ea11b3 1713 unsigned int unicode;
tgw 0:2ee762ea11b3 1714 if (!decodeUnicodeCodePoint(token, current, end, unicode))
tgw 0:2ee762ea11b3 1715 return false;
tgw 0:2ee762ea11b3 1716 decoded += codePointToUTF8(unicode);
tgw 0:2ee762ea11b3 1717 } break;
tgw 0:2ee762ea11b3 1718 default:
tgw 0:2ee762ea11b3 1719 return addError("Bad escape sequence in string", token, current);
tgw 0:2ee762ea11b3 1720 }
tgw 0:2ee762ea11b3 1721 } else {
tgw 0:2ee762ea11b3 1722 decoded += c;
tgw 0:2ee762ea11b3 1723 }
tgw 0:2ee762ea11b3 1724 }
tgw 0:2ee762ea11b3 1725 return true;
tgw 0:2ee762ea11b3 1726 }
tgw 0:2ee762ea11b3 1727
tgw 0:2ee762ea11b3 1728 bool OurReader::decodeUnicodeCodePoint(Token& token,
tgw 0:2ee762ea11b3 1729 Location& current,
tgw 0:2ee762ea11b3 1730 Location end,
tgw 0:2ee762ea11b3 1731 unsigned int& unicode) {
tgw 0:2ee762ea11b3 1732
tgw 0:2ee762ea11b3 1733 if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
tgw 0:2ee762ea11b3 1734 return false;
tgw 0:2ee762ea11b3 1735 if (unicode >= 0xD800 && unicode <= 0xDBFF) {
tgw 0:2ee762ea11b3 1736 // surrogate pairs
tgw 0:2ee762ea11b3 1737 if (end - current < 6)
tgw 0:2ee762ea11b3 1738 return addError(
tgw 0:2ee762ea11b3 1739 "additional six characters expected to parse unicode surrogate pair.",
tgw 0:2ee762ea11b3 1740 token,
tgw 0:2ee762ea11b3 1741 current);
tgw 0:2ee762ea11b3 1742 unsigned int surrogatePair;
tgw 0:2ee762ea11b3 1743 if (*(current++) == '\\' && *(current++) == 'u') {
tgw 0:2ee762ea11b3 1744 if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
tgw 0:2ee762ea11b3 1745 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
tgw 0:2ee762ea11b3 1746 } else
tgw 0:2ee762ea11b3 1747 return false;
tgw 0:2ee762ea11b3 1748 } else
tgw 0:2ee762ea11b3 1749 return addError("expecting another \\u token to begin the second half of "
tgw 0:2ee762ea11b3 1750 "a unicode surrogate pair",
tgw 0:2ee762ea11b3 1751 token,
tgw 0:2ee762ea11b3 1752 current);
tgw 0:2ee762ea11b3 1753 }
tgw 0:2ee762ea11b3 1754 return true;
tgw 0:2ee762ea11b3 1755 }
tgw 0:2ee762ea11b3 1756
tgw 0:2ee762ea11b3 1757 bool OurReader::decodeUnicodeEscapeSequence(Token& token,
tgw 0:2ee762ea11b3 1758 Location& current,
tgw 0:2ee762ea11b3 1759 Location end,
tgw 0:2ee762ea11b3 1760 unsigned int& ret_unicode) {
tgw 0:2ee762ea11b3 1761 if (end - current < 4)
tgw 0:2ee762ea11b3 1762 return addError(
tgw 0:2ee762ea11b3 1763 "Bad unicode escape sequence in string: four digits expected.",
tgw 0:2ee762ea11b3 1764 token,
tgw 0:2ee762ea11b3 1765 current);
tgw 0:2ee762ea11b3 1766 int unicode = 0;
tgw 0:2ee762ea11b3 1767 for (int index = 0; index < 4; ++index) {
tgw 0:2ee762ea11b3 1768 Char c = *current++;
tgw 0:2ee762ea11b3 1769 unicode *= 16;
tgw 0:2ee762ea11b3 1770 if (c >= '0' && c <= '9')
tgw 0:2ee762ea11b3 1771 unicode += c - '0';
tgw 0:2ee762ea11b3 1772 else if (c >= 'a' && c <= 'f')
tgw 0:2ee762ea11b3 1773 unicode += c - 'a' + 10;
tgw 0:2ee762ea11b3 1774 else if (c >= 'A' && c <= 'F')
tgw 0:2ee762ea11b3 1775 unicode += c - 'A' + 10;
tgw 0:2ee762ea11b3 1776 else
tgw 0:2ee762ea11b3 1777 return addError(
tgw 0:2ee762ea11b3 1778 "Bad unicode escape sequence in string: hexadecimal digit expected.",
tgw 0:2ee762ea11b3 1779 token,
tgw 0:2ee762ea11b3 1780 current);
tgw 0:2ee762ea11b3 1781 }
tgw 0:2ee762ea11b3 1782 ret_unicode = static_cast<unsigned int>(unicode);
tgw 0:2ee762ea11b3 1783 return true;
tgw 0:2ee762ea11b3 1784 }
tgw 0:2ee762ea11b3 1785
tgw 0:2ee762ea11b3 1786 bool
tgw 0:2ee762ea11b3 1787 OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) {
tgw 0:2ee762ea11b3 1788 ErrorInfo info;
tgw 0:2ee762ea11b3 1789 info.token_ = token;
tgw 0:2ee762ea11b3 1790 info.message_ = message;
tgw 0:2ee762ea11b3 1791 info.extra_ = extra;
tgw 0:2ee762ea11b3 1792 errors_.push_back(info);
tgw 0:2ee762ea11b3 1793 return false;
tgw 0:2ee762ea11b3 1794 }
tgw 0:2ee762ea11b3 1795
tgw 0:2ee762ea11b3 1796 bool OurReader::recoverFromError(TokenType skipUntilToken) {
tgw 0:2ee762ea11b3 1797 size_t errorCount = errors_.size();
tgw 0:2ee762ea11b3 1798 Token skip;
tgw 0:2ee762ea11b3 1799 for (;;) {
tgw 0:2ee762ea11b3 1800 if (!readToken(skip))
tgw 0:2ee762ea11b3 1801 errors_.resize(errorCount); // discard errors caused by recovery
tgw 0:2ee762ea11b3 1802 if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
tgw 0:2ee762ea11b3 1803 break;
tgw 0:2ee762ea11b3 1804 }
tgw 0:2ee762ea11b3 1805 errors_.resize(errorCount);
tgw 0:2ee762ea11b3 1806 return false;
tgw 0:2ee762ea11b3 1807 }
tgw 0:2ee762ea11b3 1808
tgw 0:2ee762ea11b3 1809 bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message,
tgw 0:2ee762ea11b3 1810 Token& token,
tgw 0:2ee762ea11b3 1811 TokenType skipUntilToken) {
tgw 0:2ee762ea11b3 1812 addError(message, token);
tgw 0:2ee762ea11b3 1813 return recoverFromError(skipUntilToken);
tgw 0:2ee762ea11b3 1814 }
tgw 0:2ee762ea11b3 1815
tgw 0:2ee762ea11b3 1816 Value& OurReader::currentValue() { return *(nodes_.top()); }
tgw 0:2ee762ea11b3 1817
tgw 0:2ee762ea11b3 1818 OurReader::Char OurReader::getNextChar() {
tgw 0:2ee762ea11b3 1819 if (current_ == end_)
tgw 0:2ee762ea11b3 1820 return 0;
tgw 0:2ee762ea11b3 1821 return *current_++;
tgw 0:2ee762ea11b3 1822 }
tgw 0:2ee762ea11b3 1823
tgw 0:2ee762ea11b3 1824 void OurReader::getLocationLineAndColumn(Location location,
tgw 0:2ee762ea11b3 1825 int& line,
tgw 0:2ee762ea11b3 1826 int& column) const {
tgw 0:2ee762ea11b3 1827 Location current = begin_;
tgw 0:2ee762ea11b3 1828 Location lastLineStart = current;
tgw 0:2ee762ea11b3 1829 line = 0;
tgw 0:2ee762ea11b3 1830 while (current < location && current != end_) {
tgw 0:2ee762ea11b3 1831 Char c = *current++;
tgw 0:2ee762ea11b3 1832 if (c == '\r') {
tgw 0:2ee762ea11b3 1833 if (*current == '\n')
tgw 0:2ee762ea11b3 1834 ++current;
tgw 0:2ee762ea11b3 1835 lastLineStart = current;
tgw 0:2ee762ea11b3 1836 ++line;
tgw 0:2ee762ea11b3 1837 } else if (c == '\n') {
tgw 0:2ee762ea11b3 1838 lastLineStart = current;
tgw 0:2ee762ea11b3 1839 ++line;
tgw 0:2ee762ea11b3 1840 }
tgw 0:2ee762ea11b3 1841 }
tgw 0:2ee762ea11b3 1842 // column & line start at 1
tgw 0:2ee762ea11b3 1843 column = int(location - lastLineStart) + 1;
tgw 0:2ee762ea11b3 1844 ++line;
tgw 0:2ee762ea11b3 1845 }
tgw 0:2ee762ea11b3 1846
tgw 0:2ee762ea11b3 1847 JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const {
tgw 0:2ee762ea11b3 1848 int line, column;
tgw 0:2ee762ea11b3 1849 getLocationLineAndColumn(location, line, column);
tgw 0:2ee762ea11b3 1850 char buffer[18 + 16 + 16 + 1];
tgw 0:2ee762ea11b3 1851 snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
tgw 0:2ee762ea11b3 1852 return buffer;
tgw 0:2ee762ea11b3 1853 }
tgw 0:2ee762ea11b3 1854
tgw 0:2ee762ea11b3 1855 JSONCPP_STRING OurReader::getFormattedErrorMessages() const {
tgw 0:2ee762ea11b3 1856 JSONCPP_STRING formattedMessage;
tgw 0:2ee762ea11b3 1857 for (Errors::const_iterator itError = errors_.begin();
tgw 0:2ee762ea11b3 1858 itError != errors_.end();
tgw 0:2ee762ea11b3 1859 ++itError) {
tgw 0:2ee762ea11b3 1860 const ErrorInfo& error = *itError;
tgw 0:2ee762ea11b3 1861 formattedMessage +=
tgw 0:2ee762ea11b3 1862 "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
tgw 0:2ee762ea11b3 1863 formattedMessage += " " + error.message_ + "\n";
tgw 0:2ee762ea11b3 1864 if (error.extra_)
tgw 0:2ee762ea11b3 1865 formattedMessage +=
tgw 0:2ee762ea11b3 1866 "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
tgw 0:2ee762ea11b3 1867 }
tgw 0:2ee762ea11b3 1868 return formattedMessage;
tgw 0:2ee762ea11b3 1869 }
tgw 0:2ee762ea11b3 1870
tgw 0:2ee762ea11b3 1871 std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
tgw 0:2ee762ea11b3 1872 std::vector<OurReader::StructuredError> allErrors;
tgw 0:2ee762ea11b3 1873 for (Errors::const_iterator itError = errors_.begin();
tgw 0:2ee762ea11b3 1874 itError != errors_.end();
tgw 0:2ee762ea11b3 1875 ++itError) {
tgw 0:2ee762ea11b3 1876 const ErrorInfo& error = *itError;
tgw 0:2ee762ea11b3 1877 OurReader::StructuredError structured;
tgw 0:2ee762ea11b3 1878 structured.offset_start = error.token_.start_ - begin_;
tgw 0:2ee762ea11b3 1879 structured.offset_limit = error.token_.end_ - begin_;
tgw 0:2ee762ea11b3 1880 structured.message = error.message_;
tgw 0:2ee762ea11b3 1881 allErrors.push_back(structured);
tgw 0:2ee762ea11b3 1882 }
tgw 0:2ee762ea11b3 1883 return allErrors;
tgw 0:2ee762ea11b3 1884 }
tgw 0:2ee762ea11b3 1885
tgw 0:2ee762ea11b3 1886 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) {
tgw 0:2ee762ea11b3 1887 ptrdiff_t length = end_ - begin_;
tgw 0:2ee762ea11b3 1888 if(value.getOffsetStart() > length
tgw 0:2ee762ea11b3 1889 || value.getOffsetLimit() > length)
tgw 0:2ee762ea11b3 1890 return false;
tgw 0:2ee762ea11b3 1891 Token token;
tgw 0:2ee762ea11b3 1892 token.type_ = tokenError;
tgw 0:2ee762ea11b3 1893 token.start_ = begin_ + value.getOffsetStart();
tgw 0:2ee762ea11b3 1894 token.end_ = end_ + value.getOffsetLimit();
tgw 0:2ee762ea11b3 1895 ErrorInfo info;
tgw 0:2ee762ea11b3 1896 info.token_ = token;
tgw 0:2ee762ea11b3 1897 info.message_ = message;
tgw 0:2ee762ea11b3 1898 info.extra_ = 0;
tgw 0:2ee762ea11b3 1899 errors_.push_back(info);
tgw 0:2ee762ea11b3 1900 return true;
tgw 0:2ee762ea11b3 1901 }
tgw 0:2ee762ea11b3 1902
tgw 0:2ee762ea11b3 1903 bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) {
tgw 0:2ee762ea11b3 1904 ptrdiff_t length = end_ - begin_;
tgw 0:2ee762ea11b3 1905 if(value.getOffsetStart() > length
tgw 0:2ee762ea11b3 1906 || value.getOffsetLimit() > length
tgw 0:2ee762ea11b3 1907 || extra.getOffsetLimit() > length)
tgw 0:2ee762ea11b3 1908 return false;
tgw 0:2ee762ea11b3 1909 Token token;
tgw 0:2ee762ea11b3 1910 token.type_ = tokenError;
tgw 0:2ee762ea11b3 1911 token.start_ = begin_ + value.getOffsetStart();
tgw 0:2ee762ea11b3 1912 token.end_ = begin_ + value.getOffsetLimit();
tgw 0:2ee762ea11b3 1913 ErrorInfo info;
tgw 0:2ee762ea11b3 1914 info.token_ = token;
tgw 0:2ee762ea11b3 1915 info.message_ = message;
tgw 0:2ee762ea11b3 1916 info.extra_ = begin_ + extra.getOffsetStart();
tgw 0:2ee762ea11b3 1917 errors_.push_back(info);
tgw 0:2ee762ea11b3 1918 return true;
tgw 0:2ee762ea11b3 1919 }
tgw 0:2ee762ea11b3 1920
tgw 0:2ee762ea11b3 1921 bool OurReader::good() const {
tgw 0:2ee762ea11b3 1922 return !errors_.size();
tgw 0:2ee762ea11b3 1923 }
tgw 0:2ee762ea11b3 1924
tgw 0:2ee762ea11b3 1925
tgw 0:2ee762ea11b3 1926 class OurCharReader : public CharReader {
tgw 0:2ee762ea11b3 1927 bool const collectComments_;
tgw 0:2ee762ea11b3 1928 OurReader reader_;
tgw 0:2ee762ea11b3 1929 public:
tgw 0:2ee762ea11b3 1930 OurCharReader(
tgw 0:2ee762ea11b3 1931 bool collectComments,
tgw 0:2ee762ea11b3 1932 OurFeatures const& features)
tgw 0:2ee762ea11b3 1933 : collectComments_(collectComments)
tgw 0:2ee762ea11b3 1934 , reader_(features)
tgw 0:2ee762ea11b3 1935 {}
tgw 0:2ee762ea11b3 1936 bool parse(
tgw 0:2ee762ea11b3 1937 char const* beginDoc, char const* endDoc,
tgw 0:2ee762ea11b3 1938 Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE {
tgw 0:2ee762ea11b3 1939 bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
tgw 0:2ee762ea11b3 1940 if (errs) {
tgw 0:2ee762ea11b3 1941 *errs = reader_.getFormattedErrorMessages();
tgw 0:2ee762ea11b3 1942 }
tgw 0:2ee762ea11b3 1943 return ok;
tgw 0:2ee762ea11b3 1944 }
tgw 0:2ee762ea11b3 1945 };
tgw 0:2ee762ea11b3 1946
tgw 0:2ee762ea11b3 1947 CharReaderBuilder::CharReaderBuilder()
tgw 0:2ee762ea11b3 1948 {
tgw 0:2ee762ea11b3 1949 setDefaults(&settings_);
tgw 0:2ee762ea11b3 1950 }
tgw 0:2ee762ea11b3 1951 CharReaderBuilder::~CharReaderBuilder()
tgw 0:2ee762ea11b3 1952 {}
tgw 0:2ee762ea11b3 1953 CharReader* CharReaderBuilder::newCharReader() const
tgw 0:2ee762ea11b3 1954 {
tgw 0:2ee762ea11b3 1955 bool collectComments = settings_["collectComments"].asBool();
tgw 0:2ee762ea11b3 1956 OurFeatures features = OurFeatures::all();
tgw 0:2ee762ea11b3 1957 features.allowComments_ = settings_["allowComments"].asBool();
tgw 0:2ee762ea11b3 1958 features.strictRoot_ = settings_["strictRoot"].asBool();
tgw 0:2ee762ea11b3 1959 features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
tgw 0:2ee762ea11b3 1960 features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
tgw 0:2ee762ea11b3 1961 features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
tgw 0:2ee762ea11b3 1962 features.stackLimit_ = settings_["stackLimit"].asInt();
tgw 0:2ee762ea11b3 1963 features.failIfExtra_ = settings_["failIfExtra"].asBool();
tgw 0:2ee762ea11b3 1964 features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
tgw 0:2ee762ea11b3 1965 features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
tgw 0:2ee762ea11b3 1966 return new OurCharReader(collectComments, features);
tgw 0:2ee762ea11b3 1967 }
tgw 0:2ee762ea11b3 1968 static void getValidReaderKeys(std::set<JSONCPP_STRING>* valid_keys)
tgw 0:2ee762ea11b3 1969 {
tgw 0:2ee762ea11b3 1970 valid_keys->clear();
tgw 0:2ee762ea11b3 1971 valid_keys->insert("collectComments");
tgw 0:2ee762ea11b3 1972 valid_keys->insert("allowComments");
tgw 0:2ee762ea11b3 1973 valid_keys->insert("strictRoot");
tgw 0:2ee762ea11b3 1974 valid_keys->insert("allowDroppedNullPlaceholders");
tgw 0:2ee762ea11b3 1975 valid_keys->insert("allowNumericKeys");
tgw 0:2ee762ea11b3 1976 valid_keys->insert("allowSingleQuotes");
tgw 0:2ee762ea11b3 1977 valid_keys->insert("stackLimit");
tgw 0:2ee762ea11b3 1978 valid_keys->insert("failIfExtra");
tgw 0:2ee762ea11b3 1979 valid_keys->insert("rejectDupKeys");
tgw 0:2ee762ea11b3 1980 valid_keys->insert("allowSpecialFloats");
tgw 0:2ee762ea11b3 1981 }
tgw 0:2ee762ea11b3 1982 bool CharReaderBuilder::validate(Json::Value* invalid) const
tgw 0:2ee762ea11b3 1983 {
tgw 0:2ee762ea11b3 1984 Json::Value my_invalid;
tgw 0:2ee762ea11b3 1985 if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
tgw 0:2ee762ea11b3 1986 Json::Value& inv = *invalid;
tgw 0:2ee762ea11b3 1987 std::set<JSONCPP_STRING> valid_keys;
tgw 0:2ee762ea11b3 1988 getValidReaderKeys(&valid_keys);
tgw 0:2ee762ea11b3 1989 Value::Members keys = settings_.getMemberNames();
tgw 0:2ee762ea11b3 1990 size_t n = keys.size();
tgw 0:2ee762ea11b3 1991 for (size_t i = 0; i < n; ++i) {
tgw 0:2ee762ea11b3 1992 JSONCPP_STRING const& key = keys[i];
tgw 0:2ee762ea11b3 1993 if (valid_keys.find(key) == valid_keys.end()) {
tgw 0:2ee762ea11b3 1994 inv[key] = settings_[key];
tgw 0:2ee762ea11b3 1995 }
tgw 0:2ee762ea11b3 1996 }
tgw 0:2ee762ea11b3 1997 return 0u == inv.size();
tgw 0:2ee762ea11b3 1998 }
tgw 0:2ee762ea11b3 1999 Value& CharReaderBuilder::operator[](JSONCPP_STRING key)
tgw 0:2ee762ea11b3 2000 {
tgw 0:2ee762ea11b3 2001 return settings_[key];
tgw 0:2ee762ea11b3 2002 }
tgw 0:2ee762ea11b3 2003 // static
tgw 0:2ee762ea11b3 2004 void CharReaderBuilder::strictMode(Json::Value* settings)
tgw 0:2ee762ea11b3 2005 {
tgw 0:2ee762ea11b3 2006 //! [CharReaderBuilderStrictMode]
tgw 0:2ee762ea11b3 2007 (*settings)["allowComments"] = false;
tgw 0:2ee762ea11b3 2008 (*settings)["strictRoot"] = true;
tgw 0:2ee762ea11b3 2009 (*settings)["allowDroppedNullPlaceholders"] = false;
tgw 0:2ee762ea11b3 2010 (*settings)["allowNumericKeys"] = false;
tgw 0:2ee762ea11b3 2011 (*settings)["allowSingleQuotes"] = false;
tgw 0:2ee762ea11b3 2012 (*settings)["stackLimit"] = 1000;
tgw 0:2ee762ea11b3 2013 (*settings)["failIfExtra"] = true;
tgw 0:2ee762ea11b3 2014 (*settings)["rejectDupKeys"] = true;
tgw 0:2ee762ea11b3 2015 (*settings)["allowSpecialFloats"] = false;
tgw 0:2ee762ea11b3 2016 //! [CharReaderBuilderStrictMode]
tgw 0:2ee762ea11b3 2017 }
tgw 0:2ee762ea11b3 2018 // static
tgw 0:2ee762ea11b3 2019 void CharReaderBuilder::setDefaults(Json::Value* settings)
tgw 0:2ee762ea11b3 2020 {
tgw 0:2ee762ea11b3 2021 //! [CharReaderBuilderDefaults]
tgw 0:2ee762ea11b3 2022 (*settings)["collectComments"] = true;
tgw 0:2ee762ea11b3 2023 (*settings)["allowComments"] = true;
tgw 0:2ee762ea11b3 2024 (*settings)["strictRoot"] = false;
tgw 0:2ee762ea11b3 2025 (*settings)["allowDroppedNullPlaceholders"] = false;
tgw 0:2ee762ea11b3 2026 (*settings)["allowNumericKeys"] = false;
tgw 0:2ee762ea11b3 2027 (*settings)["allowSingleQuotes"] = false;
tgw 0:2ee762ea11b3 2028 (*settings)["stackLimit"] = 1000;
tgw 0:2ee762ea11b3 2029 (*settings)["failIfExtra"] = false;
tgw 0:2ee762ea11b3 2030 (*settings)["rejectDupKeys"] = false;
tgw 0:2ee762ea11b3 2031 (*settings)["allowSpecialFloats"] = false;
tgw 0:2ee762ea11b3 2032 //! [CharReaderBuilderDefaults]
tgw 0:2ee762ea11b3 2033 }
tgw 0:2ee762ea11b3 2034
tgw 0:2ee762ea11b3 2035 //////////////////////////////////
tgw 0:2ee762ea11b3 2036 // global functions
tgw 0:2ee762ea11b3 2037
tgw 0:2ee762ea11b3 2038 bool parseFromStream(
tgw 0:2ee762ea11b3 2039 CharReader::Factory const& fact, JSONCPP_ISTREAM& sin,
tgw 0:2ee762ea11b3 2040 Value* root, JSONCPP_STRING* errs)
tgw 0:2ee762ea11b3 2041 {
tgw 0:2ee762ea11b3 2042 JSONCPP_OSTRINGSTREAM ssin;
tgw 0:2ee762ea11b3 2043 ssin << sin.rdbuf();
tgw 0:2ee762ea11b3 2044 JSONCPP_STRING doc = ssin.str();
tgw 0:2ee762ea11b3 2045 char const* begin = doc.data();
tgw 0:2ee762ea11b3 2046 char const* end = begin + doc.size();
tgw 0:2ee762ea11b3 2047 // Note that we do not actually need a null-terminator.
tgw 0:2ee762ea11b3 2048 CharReaderPtr const reader(fact.newCharReader());
tgw 0:2ee762ea11b3 2049 return reader->parse(begin, end, root, errs);
tgw 0:2ee762ea11b3 2050 }
tgw 0:2ee762ea11b3 2051
tgw 0:2ee762ea11b3 2052 JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) {
tgw 0:2ee762ea11b3 2053 CharReaderBuilder b;
tgw 0:2ee762ea11b3 2054 JSONCPP_STRING errs;
tgw 0:2ee762ea11b3 2055 bool ok = parseFromStream(b, sin, &root, &errs);
tgw 0:2ee762ea11b3 2056 if (!ok) {
tgw 0:2ee762ea11b3 2057 throwRuntimeError(errs);
tgw 0:2ee762ea11b3 2058 }
tgw 0:2ee762ea11b3 2059 return sin;
tgw 0:2ee762ea11b3 2060 }
tgw 0:2ee762ea11b3 2061
tgw 0:2ee762ea11b3 2062 } // namespace Json