blob: 1111a7bd063e76e1a1b414a2e139bc6cf13928b0 [file] [log] [blame]
Baptiste Lepilleur7469f1d2010-04-20 21:35:19 +00001// 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
Christopher Dunn6d135cb2007-06-13 15:51:04 +00006#ifndef CPPTL_JSON_READER_H_INCLUDED
Aaron Jacobs9fa4e842014-07-01 08:48:54 +10007#define CPPTL_JSON_READER_H_INCLUDED
Christopher Dunn6d135cb2007-06-13 15:51:04 +00008
Baptiste Lepilleureadc4782011-05-02 21:09:30 +00009#if !defined(JSON_IS_AMALGAMATION)
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100010#include "features.h"
11#include "value.h"
Baptiste Lepilleureadc4782011-05-02 21:09:30 +000012#endif // if !defined(JSON_IS_AMALGAMATION)
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100013#include <deque>
14#include <iosfwd>
15#include <stack>
16#include <string>
Christopher Dunn2c1197c2015-01-29 14:29:40 -060017#include <istream>
Christopher Dunn6d135cb2007-06-13 15:51:04 +000018
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100019// Disable warning C4251: <data member>: <type> needs to have dll-interface to
20// be used by...
Baptiste Lepilleureafd7022013-05-08 20:21:11 +000021#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100022#pragma warning(push)
23#pragma warning(disable : 4251)
Baptiste Lepilleureafd7022013-05-08 20:21:11 +000024#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
25
Christopher Dunn6d135cb2007-06-13 15:51:04 +000026namespace Json {
27
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100028/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
29 *Value.
30 *
31 */
32class JSON_API Reader {
33public:
34 typedef char Char;
Aaron Jacobs11086dd2014-09-15 10:15:29 +100035 typedef const Char* Location;
Christopher Dunn6d135cb2007-06-13 15:51:04 +000036
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100037 /** \brief An error tagged with where in the JSON text it was encountered.
38 *
39 * The offsets give the [start, limit) range of bytes within the text. Note
40 * that this is bytes, not codepoints.
41 *
Christopher Dunn6d135cb2007-06-13 15:51:04 +000042 */
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100043 struct StructuredError {
44 size_t offset_start;
45 size_t offset_limit;
46 std::string message;
47 };
48
49 /** \brief Constructs a Reader allowing all features
50 * for parsing.
51 */
52 Reader();
53
54 /** \brief Constructs a Reader allowing the specified feature set
55 * for parsing.
56 */
Aaron Jacobs11086dd2014-09-15 10:15:29 +100057 Reader(const Features& features);
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100058
59 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
60 * document.
61 * \param document UTF-8 encoded string containing the document to read.
62 * \param root [out] Contains the root value of the document if it was
63 * successfully parsed.
64 * \param collectComments \c true to collect comment and allow writing them
65 * back during
66 * serialization, \c false to discard comments.
67 * This parameter is ignored if
68 * Features::allowComments_
69 * is \c false.
70 * \return \c true if the document was successfully parsed, \c false if an
71 * error occurred.
72 */
73 bool
Aaron Jacobs11086dd2014-09-15 10:15:29 +100074 parse(const std::string& document, Value& root, bool collectComments = true);
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100075
76 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
77 document.
78 * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
79 document to read.
80 * \param endDoc Pointer on the end of the UTF-8 encoded string of the
81 document to read.
Christopher Dunn2c1197c2015-01-29 14:29:40 -060082 * Must be >= beginDoc.
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100083 * \param root [out] Contains the root value of the document if it was
84 * successfully parsed.
85 * \param collectComments \c true to collect comment and allow writing them
86 back during
87 * serialization, \c false to discard comments.
88 * This parameter is ignored if
89 Features::allowComments_
90 * is \c false.
91 * \return \c true if the document was successfully parsed, \c false if an
92 error occurred.
93 */
Aaron Jacobs11086dd2014-09-15 10:15:29 +100094 bool parse(const char* beginDoc,
95 const char* endDoc,
96 Value& root,
Aaron Jacobs9fa4e842014-07-01 08:48:54 +100097 bool collectComments = true);
98
99 /// \brief Parse from input stream.
100 /// \see Json::operator>>(std::istream&, Json::Value&).
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000101 bool parse(std::istream& is, Value& root, bool collectComments = true);
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000102
103 /** \brief Returns a user friendly string that list errors in the parsed
104 * document.
105 * \return Formatted error message with the list of errors with their location
106 * in
107 * the parsed document. An empty string is returned if no error
108 * occurred
109 * during parsing.
110 * \deprecated Use getFormattedErrorMessages() instead (typo fix).
111 */
112 JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
113 std::string getFormatedErrorMessages() const;
114
115 /** \brief Returns a user friendly string that list errors in the parsed
116 * document.
117 * \return Formatted error message with the list of errors with their location
118 * in
119 * the parsed document. An empty string is returned if no error
120 * occurred
121 * during parsing.
122 */
123 std::string getFormattedErrorMessages() const;
124
125 /** \brief Returns a vector of structured erros encounted while parsing.
126 * \return A (possibly empty) vector of StructuredError objects. Currently
127 * only one error can be returned, but the caller should tolerate
128 * multiple
129 * errors. This can occur if the parser recovers from a non-fatal
130 * parse error and then encounters additional errors.
131 */
132 std::vector<StructuredError> getStructuredErrors() const;
133
Mara Kimb84a39c2014-10-23 02:03:43 -0500134 /** \brief Add a semantic error message.
135 * \param value JSON Value location associated with the error
136 * \param message The error message.
137 * \return \c true if the error was successfully added, \c false if the
138 * Value offset exceeds the document size.
139 */
140 bool pushError(const Value& value, const std::string& message);
141
142 /** \brief Add a semantic error message with extra context.
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 std::string& message, const Value& extra);
150
151 /** \brief Return whether there are any errors.
152 * \return \c true if there are no errors to report \c false if
153 * errors have occurred.
154 */
155 bool good() const;
156
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000157private:
158 enum TokenType {
159 tokenEndOfStream = 0,
160 tokenObjectBegin,
161 tokenObjectEnd,
162 tokenArrayBegin,
163 tokenArrayEnd,
164 tokenString,
165 tokenNumber,
166 tokenTrue,
167 tokenFalse,
168 tokenNull,
169 tokenArraySeparator,
170 tokenMemberSeparator,
171 tokenComment,
172 tokenError
173 };
174
175 class Token {
176 public:
177 TokenType type_;
178 Location start_;
179 Location end_;
180 };
181
182 class ErrorInfo {
183 public:
184 Token token_;
185 std::string message_;
186 Location extra_;
187 };
188
189 typedef std::deque<ErrorInfo> Errors;
190
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000191 bool readToken(Token& token);
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000192 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();
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000200 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,
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000210 Location end,
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000211 unsigned int& unicode);
212 bool decodeUnicodeEscapeSequence(Token& token,
213 Location& current,
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000214 Location end,
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000215 unsigned int& unicode);
216 bool addError(const std::string& message, Token& token, Location extra = 0);
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000217 bool recoverFromError(TokenType skipUntilToken);
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000218 bool addErrorAndRecover(const std::string& message,
219 Token& token,
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000220 TokenType skipUntilToken);
221 void skipUntilSpace();
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000222 Value& currentValue();
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000223 Char getNextChar();
224 void
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000225 getLocationLineAndColumn(Location location, int& line, int& column) const;
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000226 std::string getLocationLineAndColumn(Location location) const;
227 void addComment(Location begin, Location end, CommentPlacement placement);
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000228 void skipCommentTokens(Token& token);
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000229
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000230 typedef std::stack<Value*> Nodes;
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000231 Nodes nodes_;
232 Errors errors_;
233 std::string document_;
234 Location begin_;
235 Location end_;
236 Location current_;
237 Location lastValueEnd_;
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000238 Value* lastValue_;
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000239 std::string commentsBefore_;
240 Features features_;
241 bool collectComments_;
Christopher Dunn2c1197c2015-01-29 14:29:40 -0600242}; // Reader
243
244/** Interface for reading JSON from a char array.
245 */
246class JSON_API CharReader {
247public:
248 virtual ~CharReader() {}
249 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
250 document.
251 * The document must be a UTF-8 encoded string containing the document to read.
252 *
253 * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
254 document to read.
255 * \param endDoc Pointer on the end of the UTF-8 encoded string of the
256 document to read.
257 * Must be >= beginDoc.
258 * \param root [out] Contains the root value of the document if it was
259 * successfully parsed.
260 * \param errs [out] Formatted error messages (if not NULL)
261 * a user friendly string that lists errors in the parsed
262 * document.
263 * \return \c true if the document was successfully parsed, \c false if an
264 error occurred.
265 */
266 virtual bool parse(
267 char const* beginDoc, char const* endDoc,
268 Value* root, std::string* errs) = 0;
269
270 class Factory {
271 public:
272 /// \brief Allocate a CharReader via operator new().
273 virtual CharReader* newCharReader() const = 0;
274 }; // Factory
275}; // CharReader
276
277class CharReaderBuilder : public CharReader::Factory {
278 bool collectComments_;
279 Features features_;
280public:
281 CharReaderBuilder();
282
283 CharReaderBuilder& withCollectComments(bool v) {
284 collectComments_ = v;
285 return *this;
286 }
287
288 CharReaderBuilder& withFeatures(Features const& v) {
289 features_ = v;
290 return *this;
291 }
292
293 virtual CharReader* newCharReader() const;
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000294};
295
Christopher Dunn2c1197c2015-01-29 14:29:40 -0600296/** Consume entire stream and use its begin/end.
297 * Someday we might have a real StreamReader, but for now this
298 * is convenient.
299 */
300bool parseFromStream(
301 CharReader::Factory const&,
302 std::istream&,
303 Value* root, std::string* errs);
304
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000305/** \brief Read from 'sin' into 'root'.
306
307 Always keep comments from the input JSON.
308
309 This can be used to read a file into a particular sub-object.
310 For example:
311 \code
312 Json::Value root;
313 cin >> root["dir"]["file"];
314 cout << root;
315 \endcode
316 Result:
317 \verbatim
318 {
319 "dir": {
320 "file": {
321 // The input stream JSON would be nested here.
322 }
323 }
324 }
325 \endverbatim
326 \throw std::exception on parse error.
327 \see Json::operator<<()
328*/
Aaron Jacobs11086dd2014-09-15 10:15:29 +1000329JSON_API std::istream& operator>>(std::istream&, Value&);
Christopher Dunn6d135cb2007-06-13 15:51:04 +0000330
331} // namespace Json
332
Baptiste Lepilleureafd7022013-05-08 20:21:11 +0000333#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
Aaron Jacobs9fa4e842014-07-01 08:48:54 +1000334#pragma warning(pop)
Baptiste Lepilleureafd7022013-05-08 20:21:11 +0000335#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
336
Christopher Dunn6d135cb2007-06-13 15:51:04 +0000337#endif // CPPTL_JSON_READER_H_INCLUDED