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