1 // Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors 2 // Distributed under MIT license, or public domain if desired and 3 // recognized in your jurisdiction. 4 // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 5 6 #ifndef CPPTL_JSON_READER_H_INCLUDED 7 #define CPPTL_JSON_READER_H_INCLUDED 8 9 #if !defined(JSON_IS_AMALGAMATION) 10 #include "features.h" 11 #include "value.h" 12 #endif // if !defined(JSON_IS_AMALGAMATION) 13 #include <deque> 14 #include <iosfwd> 15 #include <istream> 16 #include <stack> 17 #include <string> 18 19 // Disable warning C4251: <data member>: <type> needs to have dll-interface to 20 // be used by... 21 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 22 #pragma warning(push) 23 #pragma warning(disable : 4251) 24 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 25 26 #pragma pack(push, 8) 27 28 namespace Json { 29 30 /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a 31 *Value. 32 * 33 * \deprecated Use CharReader and CharReaderBuilder. 34 */ 35 class JSON_API Reader { 36 public: 37 typedef char Char; 38 typedef const Char* Location; 39 40 /** \brief An error tagged with where in the JSON text it was encountered. 41 * 42 * The offsets give the [start, limit) range of bytes within the text. Note 43 * that this is bytes, not codepoints. 44 * 45 */ 46 struct StructuredError { 47 ptrdiff_t offset_start; 48 ptrdiff_t offset_limit; 49 String message; 50 }; 51 52 /** \brief Constructs a Reader allowing all features 53 * for parsing. 54 */ 55 JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") 56 Reader(); 57 58 /** \brief Constructs a Reader allowing the specified feature set 59 * for parsing. 60 */ 61 JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") 62 Reader(const Features& features); 63 64 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> 65 * document. 66 * \param document UTF-8 encoded string containing the document to read. 67 * \param root [out] Contains the root value of the document if it was 68 * successfully parsed. 69 * \param collectComments \c true to collect comment and allow writing them 70 * back during 71 * serialization, \c false to discard comments. 72 * This parameter is ignored if 73 * Features::allowComments_ 74 * is \c false. 75 * \return \c true if the document was successfully parsed, \c false if an 76 * error occurred. 77 */ 78 bool 79 parse(const std::string& document, Value& root, bool collectComments = true); 80 81 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> 82 document. 83 * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 84 document to read. 85 * \param endDoc Pointer on the end of the UTF-8 encoded string of the 86 document to read. 87 * Must be >= beginDoc. 88 * \param root [out] Contains the root value of the document if it was 89 * successfully parsed. 90 * \param collectComments \c true to collect comment and allow writing them 91 back during 92 * serialization, \c false to discard comments. 93 * This parameter is ignored if 94 Features::allowComments_ 95 * is \c false. 96 * \return \c true if the document was successfully parsed, \c false if an 97 error occurred. 98 */ 99 bool parse(const char* beginDoc, 100 const char* endDoc, 101 Value& root, 102 bool collectComments = true); 103 104 /// \brief Parse from input stream. 105 /// \see Json::operator>>(std::istream&, Json::Value&). 106 bool parse(IStream& is, Value& root, bool collectComments = true); 107 108 /** \brief Returns a user friendly string that list errors in the parsed 109 * document. 110 * \return Formatted error message with the list of errors with their location 111 * in 112 * the parsed document. An empty string is returned if no error 113 * occurred 114 * during parsing. 115 * \deprecated Use getFormattedErrorMessages() instead (typo fix). 116 */ 117 JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") 118 String getFormatedErrorMessages() const; 119 120 /** \brief Returns a user friendly string that list errors in the parsed 121 * document. 122 * \return Formatted error message with the list of errors with their location 123 * in 124 * the parsed document. An empty string is returned if no error 125 * occurred 126 * during parsing. 127 */ 128 String getFormattedErrorMessages() const; 129 130 /** \brief Returns a vector of structured erros encounted while parsing. 131 * \return A (possibly empty) vector of StructuredError objects. Currently 132 * only one error can be returned, but the caller should tolerate 133 * multiple 134 * errors. This can occur if the parser recovers from a non-fatal 135 * parse error and then encounters additional errors. 136 */ 137 std::vector<StructuredError> getStructuredErrors() const; 138 139 /** \brief Add a semantic error message. 140 * \param value JSON Value location associated with the error 141 * \param message The error message. 142 * \return \c true if the error was successfully added, \c false if the 143 * Value offset exceeds the document size. 144 */ 145 bool pushError(const Value& value, const String& message); 146 147 /** \brief Add a semantic error message with extra context. 148 * \param value JSON Value location associated with the error 149 * \param message The error message. 150 * \param extra Additional JSON Value location to contextualize the error 151 * \return \c true if the error was successfully added, \c false if either 152 * Value offset exceeds the document size. 153 */ 154 bool pushError(const Value& value, const String& message, const Value& extra); 155 156 /** \brief Return whether there are any errors. 157 * \return \c true if there are no errors to report \c false if 158 * errors have occurred. 159 */ 160 bool good() const; 161 162 private: 163 enum TokenType { 164 tokenEndOfStream = 0, 165 tokenObjectBegin, 166 tokenObjectEnd, 167 tokenArrayBegin, 168 tokenArrayEnd, 169 tokenString, 170 tokenNumber, 171 tokenTrue, 172 tokenFalse, 173 tokenNull, 174 tokenArraySeparator, 175 tokenMemberSeparator, 176 tokenComment, 177 tokenError 178 }; 179 180 class Token { 181 public: 182 TokenType type_; 183 Location start_; 184 Location end_; 185 }; 186 187 class ErrorInfo { 188 public: 189 Token token_; 190 String message_; 191 Location extra_; 192 }; 193 194 typedef std::deque<ErrorInfo> Errors; 195 196 bool readToken(Token& token); 197 void skipSpaces(); 198 bool match(Location pattern, int patternLength); 199 bool readComment(); 200 bool readCStyleComment(); 201 bool readCppStyleComment(); 202 bool readString(); 203 void readNumber(); 204 bool readValue(); 205 bool readObject(Token& token); 206 bool readArray(Token& token); 207 bool decodeNumber(Token& token); 208 bool decodeNumber(Token& token, Value& decoded); 209 bool decodeString(Token& token); 210 bool decodeString(Token& token, String& decoded); 211 bool decodeDouble(Token& token); 212 bool decodeDouble(Token& token, Value& decoded); 213 bool decodeUnicodeCodePoint(Token& token, 214 Location& current, 215 Location end, 216 unsigned int& unicode); 217 bool decodeUnicodeEscapeSequence(Token& token, 218 Location& current, 219 Location end, 220 unsigned int& unicode); 221 bool addError(const String& message, Token& token, Location extra = nullptr); 222 bool recoverFromError(TokenType skipUntilToken); 223 bool addErrorAndRecover(const String& message, 224 Token& token, 225 TokenType skipUntilToken); 226 void skipUntilSpace(); 227 Value& currentValue(); 228 Char getNextChar(); 229 void 230 getLocationLineAndColumn(Location location, int& line, int& column) const; 231 String getLocationLineAndColumn(Location location) const; 232 void addComment(Location begin, Location end, CommentPlacement placement); 233 void skipCommentTokens(Token& token); 234 235 static bool containsNewLine(Location begin, Location end); 236 static String normalizeEOL(Location begin, Location end); 237 238 typedef std::stack<Value*> Nodes; 239 Nodes nodes_; 240 Errors errors_; 241 String document_; 242 Location begin_{}; 243 Location end_{}; 244 Location current_{}; 245 Location lastValueEnd_{}; 246 Value* lastValue_{}; 247 String commentsBefore_; 248 Features features_; 249 bool collectComments_{}; 250 }; // Reader 251 252 /** Interface for reading JSON from a char array. 253 */ 254 class JSON_API CharReader { 255 public: 256 virtual ~CharReader() = default; 257 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> 258 document. 259 * The document must be a UTF-8 encoded string containing the document to 260 read. 261 * 262 * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 263 document to read. 264 * \param endDoc Pointer on the end of the UTF-8 encoded string of the 265 document to read. 266 * Must be >= beginDoc. 267 * \param root [out] Contains the root value of the document if it was 268 * successfully parsed. 269 * \param errs [out] Formatted error messages (if not NULL) 270 * a user friendly string that lists errors in the parsed 271 * document. 272 * \return \c true if the document was successfully parsed, \c false if an 273 error occurred. 274 */ 275 virtual bool parse(char const* beginDoc, 276 char const* endDoc, 277 Value* root, 278 String* errs) = 0; 279 280 class JSON_API Factory { 281 public: 282 virtual ~Factory() = default; 283 /** \brief Allocate a CharReader via operator new(). 284 * \throw std::exception if something goes wrong (e.g. invalid settings) 285 */ 286 virtual CharReader* newCharReader() const = 0; 287 }; // Factory 288 }; // CharReader 289 290 /** \brief Build a CharReader implementation. 291 292 Usage: 293 \code 294 using namespace Json; 295 CharReaderBuilder builder; 296 builder["collectComments"] = false; 297 Value value; 298 String errs; 299 bool ok = parseFromStream(builder, std::cin, &value, &errs); 300 \endcode 301 */ 302 class JSON_API CharReaderBuilder : public CharReader::Factory { 303 public: 304 // Note: We use a Json::Value so that we can add data-members to this class 305 // without a major version bump. 306 /** Configuration of this builder. 307 These are case-sensitive. 308 Available settings (case-sensitive): 309 - `"collectComments": false or true` 310 - true to collect comment and allow writing them 311 back during serialization, false to discard comments. 312 This parameter is ignored if allowComments is false. 313 - `"allowComments": false or true` 314 - true if comments are allowed. 315 - `"strictRoot": false or true` 316 - true if root must be either an array or an object value 317 - `"allowDroppedNullPlaceholders": false or true` 318 - true if dropped null placeholders are allowed. (See 319 StreamWriterBuilder.) 320 - `"allowNumericKeys": false or true` 321 - true if numeric object keys are allowed. 322 - `"allowSingleQuotes": false or true` 323 - true if '' are allowed for strings (both keys and values) 324 - `"stackLimit": integer` 325 - Exceeding stackLimit (recursive depth of `readValue()`) will 326 cause an exception. 327 - This is a security issue (seg-faults caused by deeply nested JSON), 328 so the default is low. 329 - `"failIfExtra": false or true` 330 - If true, `parse()` returns false when extra non-whitespace trails 331 the JSON value in the input string. 332 - `"rejectDupKeys": false or true` 333 - If true, `parse()` returns false when a key is duplicated within an 334 object. 335 - `"allowSpecialFloats": false or true` 336 - If true, special float values (NaNs and infinities) are allowed 337 and their values are lossfree restorable. 338 339 You can examine 'settings_` yourself 340 to see the defaults. You can also write and read them just like any 341 JSON Value. 342 \sa setDefaults() 343 */ 344 Json::Value settings_; 345 346 CharReaderBuilder(); 347 ~CharReaderBuilder() override; 348 349 CharReader* newCharReader() const override; 350 351 /** \return true if 'settings' are legal and consistent; 352 * otherwise, indicate bad settings via 'invalid'. 353 */ 354 bool validate(Json::Value* invalid) const; 355 356 /** A simple way to update a specific setting. 357 */ 358 Value& operator[](const String& key); 359 360 /** Called by ctor, but you can use this to reset settings_. 361 * \pre 'settings' != NULL (but Json::null is fine) 362 * \remark Defaults: 363 * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults 364 */ 365 static void setDefaults(Json::Value* settings); 366 /** Same as old Features::strictMode(). 367 * \pre 'settings' != NULL (but Json::null is fine) 368 * \remark Defaults: 369 * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode 370 */ 371 static void strictMode(Json::Value* settings); 372 }; 373 374 /** Consume entire stream and use its begin/end. 375 * Someday we might have a real StreamReader, but for now this 376 * is convenient. 377 */ 378 bool JSON_API parseFromStream(CharReader::Factory const&, 379 IStream&, 380 Value* root, 381 String* errs); 382 383 /** \brief Read from 'sin' into 'root'. 384 385 Always keep comments from the input JSON. 386 387 This can be used to read a file into a particular sub-object. 388 For example: 389 \code 390 Json::Value root; 391 cin >> root["dir"]["file"]; 392 cout << root; 393 \endcode 394 Result: 395 \verbatim 396 { 397 "dir": { 398 "file": { 399 // The input stream JSON would be nested here. 400 } 401 } 402 } 403 \endverbatim 404 \throw std::exception on parse error. 405 \see Json::operator<<() 406 */ 407 JSON_API IStream& operator>>(IStream&, Value&); 408 409 } // namespace Json 410 411 #pragma pack(pop) 412 413 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 414 #pragma warning(pop) 415 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 416 417 #endif // CPPTL_JSON_READER_H_INCLUDED 418