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