1// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
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 JSON_READER_H_INCLUDED
7#define JSON_READER_H_INCLUDED
8
9#if !defined(JSON_IS_AMALGAMATION)
10#include "json_features.h"
11#include "value.h"
12#endif // if !defined(JSON_IS_AMALGAMATION)
13#include <deque>
14#include <iosfwd>
15#include <istream>
16#include <stack>
17#include <string>
18
19// Disable warning C4251: <data member>: <type> needs to have dll-interface to
20// be used by...
21#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
22#pragma warning(push)
23#pragma warning(disable : 4251)
24#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
25
26#pragma pack(push, 8)
27
28namespace Json {
29
30/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
31 * Value.
32 *
33 * \deprecated Use CharReader and CharReaderBuilder.
34 */
35
36class JSONCPP_DEPRECATED(
37 "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
38public:
39 using Char = char;
40 using Location = const Char*;
41
42 /** \brief An error tagged with where in the JSON text it was encountered.
43 *
44 * The offsets give the [start, limit) range of bytes within the text. Note
45 * that this is bytes, not codepoints.
46 */
47 struct StructuredError {
48 ptrdiff_t offset_start;
49 ptrdiff_t offset_limit;
50 String message;
51 };
52
53 /** \brief Constructs a Reader allowing all features for parsing.
54 */
55 JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
56 Reader();
57
58 /** \brief Constructs a Reader allowing the specified feature set for parsing.
59 */
60 JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
61 Reader(const Features& features);
62
63 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
64 * document.
65 *
66 * \param document UTF-8 encoded string containing the document
67 * to read.
68 * \param[out] root Contains the root value of the document if it
69 * was successfully parsed.
70 * \param collectComments \c true to collect comment and allow writing
71 * them back during serialization, \c false to
72 * discard comments. This parameter is ignored
73 * if Features::allowComments_ is \c false.
74 * \return \c true if the document was successfully parsed, \c false if an
75 * error occurred.
76 */
77 bool parse(const std::string& document, Value& root,
78 bool collectComments = true);
79
80 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
81 * document.
82 *
83 * \param beginDoc Pointer on the beginning of the UTF-8 encoded
84 * string of the document to read.
85 * \param endDoc Pointer on the end of the UTF-8 encoded string
86 * of the document to read. Must be >= beginDoc.
87 * \param[out] root Contains the root value of the document if it
88 * was successfully parsed.
89 * \param collectComments \c true to collect comment and allow writing
90 * them back during serialization, \c false to
91 * discard comments. This parameter is ignored
92 * if Features::allowComments_ is \c false.
93 * \return \c true if the document was successfully parsed, \c false if an
94 * error occurred.
95 */
96 bool parse(const char* beginDoc, const char* endDoc, Value& root,
97 bool collectComments = true);
98
99 /// \brief Parse from input stream.
100 /// \see Json::operator>>(std::istream&, Json::Value&).
101 bool parse(IStream& is, Value& root, bool collectComments = true);
102
103 /** \brief Returns a user friendly string that list errors in the parsed
104 * document.
105 *
106 * \return Formatted error message with the list of errors with their
107 * location in the parsed document. An empty string is returned if no error
108 * occurred during parsing.
109 * \deprecated Use getFormattedErrorMessages() instead (typo fix).
110 */
111 JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
112 String getFormatedErrorMessages() const;
113
114 /** \brief Returns a user friendly string that list errors in the parsed
115 * document.
116 *
117 * \return Formatted error message with the list of errors with their
118 * location in the parsed document. An empty string is returned if no error
119 * occurred during parsing.
120 */
121 String getFormattedErrorMessages() const;
122
123 /** \brief Returns a vector of structured errors encountered while parsing.
124 *
125 * \return A (possibly empty) vector of StructuredError objects. Currently
126 * only one error can be returned, but the caller should tolerate multiple
127 * errors. This can occur if the parser recovers from a non-fatal parse
128 * error and then encounters additional errors.
129 */
130 std::vector<StructuredError> getStructuredErrors() const;
131
132 /** \brief Add a semantic error message.
133 *
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 Value
137 * offset exceeds the document size.
138 */
139 bool pushError(const Value& value, const String& message);
140
141 /** \brief Add a semantic error message with extra context.
142 *
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 String& message, const Value& extra);
150
151 /** \brief Return whether there are any errors.
152 *
153 * \return \c true if there are no errors to report \c false if errors have
154 * occurred.
155 */
156 bool good() const;
157
158private:
159 enum TokenType {
160 tokenEndOfStream = 0,
161 tokenObjectBegin,
162 tokenObjectEnd,
163 tokenArrayBegin,
164 tokenArrayEnd,
165 tokenString,
166 tokenNumber,
167 tokenTrue,
168 tokenFalse,
169 tokenNull,
170 tokenArraySeparator,
171 tokenMemberSeparator,
172 tokenComment,
173 tokenError
174 };
175
176 class Token {
177 public:
178 TokenType type_;
179 Location start_;
180 Location end_;
181 };
182
183 class ErrorInfo {
184 public:
185 Token token_;
186 String message_;
187 Location extra_;
188 };
189
190 using Errors = std::deque<ErrorInfo>;
191
192 bool readToken(Token& token);
193 void skipSpaces();
194 bool match(const Char* pattern, int patternLength);
195 bool readComment();
196 bool readCStyleComment();
197 bool readCppStyleComment();
198 bool readString();
199 void readNumber();
200 bool readValue();
201 bool readObject(Token& token);
202 bool readArray(Token& token);
203 bool decodeNumber(Token& token);
204 bool decodeNumber(Token& token, Value& decoded);
205 bool decodeString(Token& token);
206 bool decodeString(Token& token, String& decoded);
207 bool decodeDouble(Token& token);
208 bool decodeDouble(Token& token, Value& decoded);
209 bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
210 unsigned int& unicode);
211 bool decodeUnicodeEscapeSequence(Token& token, Location& current,
212 Location end, unsigned int& unicode);
213 bool addError(const String& message, Token& token, Location extra = nullptr);
214 bool recoverFromError(TokenType skipUntilToken);
215 bool addErrorAndRecover(const String& message, Token& token,
216 TokenType skipUntilToken);
217 void skipUntilSpace();
218 Value& currentValue();
219 Char getNextChar();
220 void getLocationLineAndColumn(Location location, int& line,
221 int& column) const;
222 String getLocationLineAndColumn(Location location) const;
223 void addComment(Location begin, Location end, CommentPlacement placement);
224 void skipCommentTokens(Token& token);
225
226 static bool containsNewLine(Location begin, Location end);
227 static String normalizeEOL(Location begin, Location end);
228
229 using Nodes = std::stack<Value*>;
230 Nodes nodes_;
231 Errors errors_;
232 String document_;
233 Location begin_{};
234 Location end_{};
235 Location current_{};
236 Location lastValueEnd_{};
237 Value* lastValue_{};
238 String commentsBefore_;
239 Features features_;
240 bool collectComments_{};
241}; // Reader
242
243/** Interface for reading JSON from a char array.
244 */
245class JSON_API CharReader {
246public:
247 virtual ~CharReader() = default;
248 /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
249 * document. The document must be a UTF-8 encoded string containing the
250 * document to read.
251 *
252 * \param beginDoc Pointer on the beginning of the UTF-8 encoded string
253 * of the document to read.
254 * \param endDoc Pointer on the end of the UTF-8 encoded string of the
255 * document to read. Must be >= beginDoc.
256 * \param[out] root Contains the root value of the document if it was
257 * successfully parsed.
258 * \param[out] errs Formatted error messages (if not NULL) a user
259 * friendly string that lists errors in the parsed
260 * document.
261 * \return \c true if the document was successfully parsed, \c false if an
262 * error occurred.
263 */
264 virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
265 String* errs) = 0;
266
267 class JSON_API Factory {
268 public:
269 virtual ~Factory() = default;
270 /** \brief Allocate a CharReader via operator new().
271 * \throw std::exception if something goes wrong (e.g. invalid settings)
272 */
273 virtual CharReader* newCharReader() const = 0;
274 }; // Factory
275}; // CharReader
276
277/** \brief Build a CharReader implementation.
278 *
279 * Usage:
280 * \code
281 * using namespace Json;
282 * CharReaderBuilder builder;
283 * builder["collectComments"] = false;
284 * Value value;
285 * String errs;
286 * bool ok = parseFromStream(builder, std::cin, &value, &errs);
287 * \endcode
288 */
289class JSON_API CharReaderBuilder : public CharReader::Factory {
290public:
291 // Note: We use a Json::Value so that we can add data-members to this class
292 // without a major version bump.
293 /** Configuration of this builder.
294 * These are case-sensitive.
295 * Available settings (case-sensitive):
296 * - `"collectComments": false or true`
297 * - true to collect comment and allow writing them back during
298 * serialization, false to discard comments. This parameter is ignored
299 * if allowComments is false.
300 * - `"allowComments": false or true`
301 * - true if comments are allowed.
302 * - `"allowTrailingCommas": false or true`
303 * - true if trailing commas in objects and arrays are allowed.
304 * - `"strictRoot": false or true`
305 * - true if root must be either an array or an object value
306 * - `"allowDroppedNullPlaceholders": false or true`
307 * - true if dropped null placeholders are allowed. (See
308 * StreamWriterBuilder.)
309 * - `"allowNumericKeys": false or true`
310 * - true if numeric object keys are allowed.
311 * - `"allowSingleQuotes": false or true`
312 * - true if '' are allowed for strings (both keys and values)
313 * - `"stackLimit": integer`
314 * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
315 * exception.
316 * - This is a security issue (seg-faults caused by deeply nested JSON), so
317 * the default is low.
318 * - `"failIfExtra": false or true`
319 * - If true, `parse()` returns false when extra non-whitespace trails the
320 * JSON value in the input string.
321 * - `"rejectDupKeys": false or true`
322 * - If true, `parse()` returns false when a key is duplicated within an
323 * object.
324 * - `"allowSpecialFloats": false or true`
325 * - If true, special float values (NaNs and infinities) are allowed and
326 * their values are lossfree restorable.
327 *
328 * You can examine 'settings_` yourself to see the defaults. You can also
329 * write and read them just like any JSON Value.
330 * \sa setDefaults()
331 */
332 Json::Value settings_;
333
334 CharReaderBuilder();
335 ~CharReaderBuilder() override;
336
337 CharReader* newCharReader() const override;
338
339 /** \return true if 'settings' are legal and consistent;
340 * otherwise, indicate bad settings via 'invalid'.
341 */
342 bool validate(Json::Value* invalid) const;
343
344 /** A simple way to update a specific setting.
345 */
346 Value& operator[](const String& key);
347
348 /** Called by ctor, but you can use this to reset settings_.
349 * \pre 'settings' != NULL (but Json::null is fine)
350 * \remark Defaults:
351 * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
352 */
353 static void setDefaults(Json::Value* settings);
354 /** Same as old Features::strictMode().
355 * \pre 'settings' != NULL (but Json::null is fine)
356 * \remark Defaults:
357 * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
358 */
359 static void strictMode(Json::Value* settings);
360};
361
362/** Consume entire stream and use its begin/end.
363 * Someday we might have a real StreamReader, but for now this
364 * is convenient.
365 */
366bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
367 String* errs);
368
369/** \brief Read from 'sin' into 'root'.
370 *
371 * Always keep comments from the input JSON.
372 *
373 * This can be used to read a file into a particular sub-object.
374 * For example:
375 * \code
376 * Json::Value root;
377 * cin >> root["dir"]["file"];
378 * cout << root;
379 * \endcode
380 * Result:
381 * \verbatim
382 * {
383 * "dir": {
384 * "file": {
385 * // The input stream JSON would be nested here.
386 * }
387 * }
388 * }
389 * \endverbatim
390 * \throw std::exception on parse error.
391 * \see Json::operator<<()
392 */
393JSON_API IStream& operator>>(IStream&, Value&);
394
395} // namespace Json
396
397#pragma pack(pop)
398
399#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
400#pragma warning(pop)
401#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
402
403#endif // JSON_READER_H_INCLUDED
404