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 <stack>
15# include <string>
16
17namespace Json {
18
19   /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
20    *
21    */
22   class JSON_API Reader
23   {
24   public:
25      typedef char Char;
26      typedef const Char *Location;
27
28      /** \brief Constructs a Reader allowing all features
29       * for parsing.
30       */
31      Reader();
32
33      /** \brief Constructs a Reader allowing the specified feature set
34       * for parsing.
35       */
36      Reader( const Features &features );
37
38      /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
39       * \param document UTF-8 encoded string containing the document to read.
40       * \param root [out] Contains the root value of the document if it was
41       *             successfully parsed.
42       * \param collectComments \c true to collect comment and allow writing them back during
43       *                        serialization, \c false to discard comments.
44       *                        This parameter is ignored if Features::allowComments_
45       *                        is \c false.
46       * \return \c true if the document was successfully parsed, \c false if an error occurred.
47       */
48      bool parse( const std::string &document,
49                  Value &root,
50                  bool collectComments = true );
51
52      /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
53       * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
54       * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read.
55       \               Must be >= beginDoc.
56       * \param root [out] Contains the root value of the document if it was
57       *             successfully parsed.
58       * \param collectComments \c true to collect comment and allow writing them back during
59       *                        serialization, \c false to discard comments.
60       *                        This parameter is ignored if Features::allowComments_
61       *                        is \c false.
62       * \return \c true if the document was successfully parsed, \c false if an error occurred.
63       */
64      bool parse( const char *beginDoc, const char *endDoc,
65                  Value &root,
66                  bool collectComments = true );
67
68      /// \brief Parse from input stream.
69      /// \see Json::operator>>(std::istream&, Json::Value&).
70      bool parse( std::istream &is,
71                  Value &root,
72                  bool collectComments = true );
73
74      /** \brief Returns a user friendly string that list errors in the parsed document.
75       * \return Formatted error message with the list of errors with their location in
76       *         the parsed document. An empty string is returned if no error occurred
77       *         during parsing.
78       * \deprecated Use getFormattedErrorMessages() instead (typo fix).
79       */
80      JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
81      std::string getFormatedErrorMessages() const;
82
83      /** \brief Returns a user friendly string that list errors in the parsed document.
84       * \return Formatted error message with the list of errors with their location in
85       *         the parsed document. An empty string is returned if no error occurred
86       *         during parsing.
87       */
88      std::string getFormattedErrorMessages() const;
89
90   private:
91      enum TokenType
92      {
93         tokenEndOfStream = 0,
94         tokenObjectBegin,
95         tokenObjectEnd,
96         tokenArrayBegin,
97         tokenArrayEnd,
98         tokenString,
99         tokenNumber,
100         tokenTrue,
101         tokenFalse,
102         tokenNull,
103         tokenArraySeparator,
104         tokenMemberSeparator,
105         tokenComment,
106         tokenError
107      };
108
109      class Token
110      {
111      public:
112         TokenType type_;
113         Location start_;
114         Location end_;
115      };
116
117      class ErrorInfo
118      {
119      public:
120         Token token_;
121         std::string message_;
122         Location extra_;
123      };
124
125      typedef std::deque<ErrorInfo> Errors;
126
127      bool expectToken( TokenType type, Token &token, const char *message );
128      bool readToken( Token &token );
129      void skipSpaces();
130      bool match( Location pattern,
131                  int patternLength );
132      bool readComment();
133      bool readCStyleComment();
134      bool readCppStyleComment();
135      bool readString();
136      void readNumber();
137      bool readValue();
138      bool readObject( Token &token );
139      bool readArray( Token &token );
140      bool decodeNumber( Token &token );
141      bool decodeString( Token &token );
142      bool decodeString( Token &token, std::string &decoded );
143      bool decodeDouble( Token &token );
144      bool decodeUnicodeCodePoint( Token &token,
145                                   Location &current,
146                                   Location end,
147                                   unsigned int &unicode );
148      bool decodeUnicodeEscapeSequence( Token &token,
149                                        Location &current,
150                                        Location end,
151                                        unsigned int &unicode );
152      bool addError( const std::string &message,
153                     Token &token,
154                     Location extra = 0 );
155      bool recoverFromError( TokenType skipUntilToken );
156      bool addErrorAndRecover( const std::string &message,
157                               Token &token,
158                               TokenType skipUntilToken );
159      void skipUntilSpace();
160      Value &currentValue();
161      Char getNextChar();
162      void getLocationLineAndColumn( Location location,
163                                     int &line,
164                                     int &column ) const;
165      std::string getLocationLineAndColumn( Location location ) const;
166      void addComment( Location begin,
167                       Location end,
168                       CommentPlacement placement );
169      void skipCommentTokens( Token &token );
170
171      typedef std::stack<Value *> Nodes;
172      Nodes nodes_;
173      Errors errors_;
174      std::string document_;
175      Location begin_;
176      Location end_;
177      Location current_;
178      Location lastValueEnd_;
179      Value *lastValue_;
180      std::string commentsBefore_;
181      Features features_;
182      bool collectComments_;
183   };
184
185   /** \brief Read from 'sin' into 'root'.
186
187    Always keep comments from the input JSON.
188
189    This can be used to read a file into a particular sub-object.
190    For example:
191    \code
192    Json::Value root;
193    cin >> root["dir"]["file"];
194    cout << root;
195    \endcode
196    Result:
197    \verbatim
198    {
199    "dir": {
200        "file": {
201        // The input stream JSON would be nested here.
202        }
203    }
204    }
205    \endverbatim
206    \throw std::exception on parse error.
207    \see Json::operator<<()
208   */
209   std::istream& operator>>( std::istream&, Value& );
210
211} // namespace Json
212
213#endif // CPPTL_JSON_READER_H_INCLUDED
214