1 // Copyright 2007-2010 Baptiste Lepilleur 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 <stack> 16 #include <string> 17 18 // Disable warning C4251: <data member>: <type> needs to have dll-interface to 19 // be used by... 20 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 21 #pragma warning(push) 22 #pragma warning(disable : 4251) 23 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 24 25 namespace Json { 26 27 /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a 28 *Value. 29 * 30 */ 31 class JSON_API Reader { 32 public: 33 typedef char Char; 34 typedef const Char* Location; 35 36 /** \brief An error tagged with where in the JSON text it was encountered. 37 * 38 * The offsets give the [start, limit) range of bytes within the text. Note 39 * that this is bytes, not codepoints. 40 * 41 */ 42 struct StructuredError { 43 size_t offset_start; 44 size_t offset_limit; 45 std::string message; 46 }; 47 48 /** \brief Constructs a Reader allowing all features 49 * for parsing. 50 */ 51 Reader(); 52 53 /** \brief Constructs a Reader allowing the specified feature set 54 * for parsing. 55 */ 56 Reader(const Features& features); 57 58 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> 59 * document. 60 * \param document UTF-8 encoded string containing the document to read. 61 * \param root [out] Contains the root value of the document if it was 62 * successfully parsed. 63 * \param collectComments \c true to collect comment and allow writing them 64 * back during 65 * serialization, \c false to discard comments. 66 * This parameter is ignored if 67 * Features::allowComments_ 68 * is \c false. 69 * \return \c true if the document was successfully parsed, \c false if an 70 * error occurred. 71 */ 72 bool 73 parse(const std::string& document, Value& root, bool collectComments = true); 74 75 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> 76 document. 77 * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the 78 document to read. 79 * \param endDoc Pointer on the end of the UTF-8 encoded string of the 80 document to read. 81 \ Must be >= beginDoc. 82 * \param root [out] Contains the root value of the document if it was 83 * successfully parsed. 84 * \param collectComments \c true to collect comment and allow writing them 85 back during 86 * serialization, \c false to discard comments. 87 * This parameter is ignored if 88 Features::allowComments_ 89 * is \c false. 90 * \return \c true if the document was successfully parsed, \c false if an 91 error occurred. 92 */ 93 bool parse(const char* beginDoc, 94 const char* endDoc, 95 Value& root, 96 bool collectComments = true); 97 98 /// \brief Parse from input stream. 99 /// \see Json::operator>>(std::istream&, Json::Value&). 100 bool parse(std::istream& is, Value& root, bool collectComments = true); 101 102 /** \brief Returns a user friendly string that list errors in the parsed 103 * document. 104 * \return Formatted error message with the list of errors with their location 105 * in 106 * the parsed document. An empty string is returned if no error 107 * occurred 108 * during parsing. 109 * \deprecated Use getFormattedErrorMessages() instead (typo fix). 110 */ 111 JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") 112 std::string getFormatedErrorMessages() const; 113 114 /** \brief Returns a user friendly string that list errors in the parsed 115 * document. 116 * \return Formatted error message with the list of errors with their location 117 * in 118 * the parsed document. An empty string is returned if no error 119 * occurred 120 * during parsing. 121 */ 122 std::string getFormattedErrorMessages() const; 123 124 /** \brief Returns a vector of structured erros encounted while parsing. 125 * \return A (possibly empty) vector of StructuredError objects. Currently 126 * only one error can be returned, but the caller should tolerate 127 * multiple 128 * errors. This can occur if the parser recovers from a non-fatal 129 * parse error and then encounters additional errors. 130 */ 131 std::vector<StructuredError> getStructuredErrors() const; 132 133 /** \brief Add a semantic error message. 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 137 * Value offset exceeds the document size. 138 */ 139 bool pushError(const Value& value, const std::string& message); 140 141 /** \brief Add a semantic error message with extra context. 142 * \param value JSON Value location associated with the error 143 * \param message The error message. 144 * \param extra Additional JSON Value location to contextualize the error 145 * \return \c true if the error was successfully added, \c false if either 146 * Value offset exceeds the document size. 147 */ 148 bool pushError(const Value& value, const std::string& message, const Value& extra); 149 150 /** \brief Return whether there are any errors. 151 * \return \c true if there are no errors to report \c false if 152 * errors have occurred. 153 */ 154 bool good() const; 155 156 private: 157 enum TokenType { 158 tokenEndOfStream = 0, 159 tokenObjectBegin, 160 tokenObjectEnd, 161 tokenArrayBegin, 162 tokenArrayEnd, 163 tokenString, 164 tokenNumber, 165 tokenTrue, 166 tokenFalse, 167 tokenNull, 168 tokenArraySeparator, 169 tokenMemberSeparator, 170 tokenComment, 171 tokenError 172 }; 173 174 class Token { 175 public: 176 TokenType type_; 177 Location start_; 178 Location end_; 179 }; 180 181 class ErrorInfo { 182 public: 183 Token token_; 184 std::string message_; 185 Location extra_; 186 }; 187 188 typedef std::deque<ErrorInfo> Errors; 189 190 bool expectToken(TokenType type, Token& token, const char* message); 191 bool readToken(Token& token); 192 void skipSpaces(); 193 bool match(Location pattern, int patternLength); 194 bool readComment(); 195 bool readCStyleComment(); 196 bool readCppStyleComment(); 197 bool readString(); 198 void readNumber(); 199 bool readValue(); 200 bool readObject(Token& token); 201 bool readArray(Token& token); 202 bool decodeNumber(Token& token); 203 bool decodeNumber(Token& token, Value& decoded); 204 bool decodeString(Token& token); 205 bool decodeString(Token& token, std::string& decoded); 206 bool decodeDouble(Token& token); 207 bool decodeDouble(Token& token, Value& decoded); 208 bool decodeUnicodeCodePoint(Token& token, 209 Location& current, 210 Location end, 211 unsigned int& unicode); 212 bool decodeUnicodeEscapeSequence(Token& token, 213 Location& current, 214 Location end, 215 unsigned int& unicode); 216 bool addError(const std::string& message, Token& token, Location extra = 0); 217 bool recoverFromError(TokenType skipUntilToken); 218 bool addErrorAndRecover(const std::string& message, 219 Token& token, 220 TokenType skipUntilToken); 221 void skipUntilSpace(); 222 Value& currentValue(); 223 Char getNextChar(); 224 void 225 getLocationLineAndColumn(Location location, int& line, int& column) const; 226 std::string getLocationLineAndColumn(Location location) const; 227 void addComment(Location begin, Location end, CommentPlacement placement); 228 void skipCommentTokens(Token& token); 229 230 typedef std::stack<Value*> Nodes; 231 Nodes nodes_; 232 Errors errors_; 233 std::string document_; 234 Location begin_; 235 Location end_; 236 Location current_; 237 Location lastValueEnd_; 238 Value* lastValue_; 239 std::string commentsBefore_; 240 Features features_; 241 bool collectComments_; 242 }; 243 244 /** \brief Read from 'sin' into 'root'. 245 246 Always keep comments from the input JSON. 247 248 This can be used to read a file into a particular sub-object. 249 For example: 250 \code 251 Json::Value root; 252 cin >> root["dir"]["file"]; 253 cout << root; 254 \endcode 255 Result: 256 \verbatim 257 { 258 "dir": { 259 "file": { 260 // The input stream JSON would be nested here. 261 } 262 } 263 } 264 \endverbatim 265 \throw std::exception on parse error. 266 \see Json::operator<<() 267 */ 268 JSON_API std::istream& operator>>(std::istream&, Value&); 269 270 } // namespace Json 271 272 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 273 #pragma warning(pop) 274 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) 275 276 #endif // CPPTL_JSON_READER_H_INCLUDED 277