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
25namespace Json {
26
27/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
28 *Value.
29 *
30 */
31class JSON_API Reader {
32public:
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
156private:
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*/
268JSON_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