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