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