/src/jsoncpp/include/json/reader.h
Line | Count | Source |
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) |
27 | | #pragma pack() |
28 | | |
29 | | namespace Json { |
30 | | |
31 | | /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a |
32 | | * Value. |
33 | | * |
34 | | * \deprecated Use CharReader and CharReaderBuilder. |
35 | | */ |
36 | | |
37 | | class JSON_API Reader { |
38 | | public: |
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 | | * \deprecated Use CharReader and CharReaderBuilder. |
55 | | */ |
56 | | Reader(); |
57 | | |
58 | | /** \brief Constructs a Reader allowing the specified feature set for parsing. |
59 | | * \deprecated Use CharReader and CharReaderBuilder. |
60 | | */ |
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 | | |
158 | | private: |
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 | | bool readTokenSkippingComments(Token& token); |
194 | | void skipSpaces(); |
195 | | bool match(const Char* pattern, int patternLength); |
196 | | bool readComment(); |
197 | | bool readCStyleComment(); |
198 | | bool readCppStyleComment(); |
199 | | bool readString(); |
200 | | void readNumber(); |
201 | | bool readValue(); |
202 | | bool readObject(Token& token); |
203 | | bool readArray(Token& token); |
204 | | bool decodeNumber(Token& token); |
205 | | bool decodeNumber(Token& token, Value& decoded); |
206 | | bool decodeString(Token& token); |
207 | | bool decodeString(Token& token, String& decoded); |
208 | | bool decodeDouble(Token& token); |
209 | | bool decodeDouble(Token& token, Value& decoded); |
210 | | bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, |
211 | | unsigned int& unicode); |
212 | | bool decodeUnicodeEscapeSequence(Token& token, Location& current, |
213 | | Location end, unsigned int& unicode); |
214 | | bool addError(const String& message, Token& token, Location extra = nullptr); |
215 | | bool recoverFromError(TokenType skipUntilToken); |
216 | | bool addErrorAndRecover(const String& message, Token& token, |
217 | | TokenType skipUntilToken); |
218 | | void skipUntilSpace(); |
219 | | Value& currentValue(); |
220 | | Char getNextChar(); |
221 | | void getLocationLineAndColumn(Location location, int& line, |
222 | | int& column) const; |
223 | | String getLocationLineAndColumn(Location location) const; |
224 | | void addComment(Location begin, Location end, CommentPlacement placement); |
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 | | */ |
245 | | class JSON_API CharReader { |
246 | | public: |
247 | | struct JSON_API StructuredError { |
248 | | ptrdiff_t offset_start; |
249 | | ptrdiff_t offset_limit; |
250 | | String message; |
251 | | }; |
252 | | |
253 | 5.94k | virtual ~CharReader() = default; |
254 | | /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> |
255 | | * document. The document must be a UTF-8 encoded string containing the |
256 | | * document to read. |
257 | | * |
258 | | * \param beginDoc Pointer on the beginning of the UTF-8 encoded string |
259 | | * of the document to read. |
260 | | * \param endDoc Pointer on the end of the UTF-8 encoded string of the |
261 | | * document to read. Must be >= beginDoc. |
262 | | * \param[out] root Contains the root value of the document if it was |
263 | | * successfully parsed. |
264 | | * \param[out] errs Formatted error messages (if not NULL) a user |
265 | | * friendly string that lists errors in the parsed |
266 | | * document. |
267 | | * \return \c true if the document was successfully parsed, \c false if an |
268 | | * error occurred. |
269 | | */ |
270 | | virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, |
271 | | String* errs); |
272 | | |
273 | | /** \brief Returns a vector of structured errors encountered while parsing. |
274 | | * Each parse call resets the stored list of errors. |
275 | | */ |
276 | | std::vector<StructuredError> getStructuredErrors() const; |
277 | | |
278 | | class JSON_API Factory { |
279 | | public: |
280 | 5.94k | virtual ~Factory() = default; |
281 | | /** \brief Allocate a CharReader via operator new(). |
282 | | * \throw std::exception if something goes wrong (e.g. invalid settings) |
283 | | */ |
284 | | virtual CharReader* newCharReader() const = 0; |
285 | | }; // Factory |
286 | | |
287 | | protected: |
288 | | class Impl { |
289 | | public: |
290 | 5.94k | virtual ~Impl() = default; |
291 | | virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, |
292 | | String* errs) = 0; |
293 | | virtual std::vector<StructuredError> getStructuredErrors() const = 0; |
294 | | }; |
295 | | |
296 | 5.94k | explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {} |
297 | | |
298 | | private: |
299 | | std::unique_ptr<Impl> _impl; |
300 | | }; // CharReader |
301 | | |
302 | | /** \brief Build a CharReader implementation. |
303 | | * |
304 | | * Usage: |
305 | | * \code |
306 | | * using namespace Json; |
307 | | * CharReaderBuilder builder; |
308 | | * builder["collectComments"] = false; |
309 | | * Value value; |
310 | | * String errs; |
311 | | * bool ok = parseFromStream(builder, std::cin, &value, &errs); |
312 | | * \endcode |
313 | | */ |
314 | | class JSON_API CharReaderBuilder : public CharReader::Factory { |
315 | | public: |
316 | | // Note: We use a Json::Value so that we can add data-members to this class |
317 | | // without a major version bump. |
318 | | /** Configuration of this builder. |
319 | | * These are case-sensitive. |
320 | | * Available settings (case-sensitive): |
321 | | * - `"collectComments": false or true` |
322 | | * - true to collect comment and allow writing them back during |
323 | | * serialization, false to discard comments. This parameter is ignored |
324 | | * if allowComments is false. |
325 | | * - `"allowComments": false or true` |
326 | | * - true if comments are allowed. |
327 | | * - `"allowTrailingCommas": false or true` |
328 | | * - true if trailing commas in objects and arrays are allowed. |
329 | | * - `"strictRoot": false or true` |
330 | | * - true if root must be either an array or an object value |
331 | | * - `"allowDroppedNullPlaceholders": false or true` |
332 | | * - true if dropped null placeholders are allowed. (See |
333 | | * StreamWriterBuilder.) |
334 | | * - `"allowNumericKeys": false or true` |
335 | | * - true if numeric object keys are allowed. |
336 | | * - `"allowSingleQuotes": false or true` |
337 | | * - true if '' are allowed for strings (both keys and values) |
338 | | * - `"stackLimit": integer` |
339 | | * - Exceeding stackLimit (recursive depth of `readValue()`) will cause an |
340 | | * exception. |
341 | | * - This is a security issue (seg-faults caused by deeply nested JSON), so |
342 | | * the default is low. |
343 | | * - `"failIfExtra": false or true` |
344 | | * - If true, `parse()` returns false when extra non-whitespace trails the |
345 | | * JSON value in the input string. |
346 | | * - `"rejectDupKeys": false or true` |
347 | | * - If true, `parse()` returns false when a key is duplicated within an |
348 | | * object. |
349 | | * - `"allowSpecialFloats": false or true` |
350 | | * - If true, special float values (NaNs and infinities) are allowed and |
351 | | * their values are lossfree restorable. |
352 | | * - `"skipBom": false or true` |
353 | | * - If true, if the input starts with the Unicode byte order mark (BOM), |
354 | | * it is skipped. |
355 | | * |
356 | | * You can examine 'settings_` yourself to see the defaults. You can also |
357 | | * write and read them just like any JSON Value. |
358 | | * \sa setDefaults() |
359 | | */ |
360 | | Json::Value settings_; |
361 | | |
362 | | CharReaderBuilder(); |
363 | | ~CharReaderBuilder() override; |
364 | | |
365 | | CharReader* newCharReader() const override; |
366 | | |
367 | | /** \return true if 'settings' are legal and consistent; |
368 | | * otherwise, indicate bad settings via 'invalid'. |
369 | | */ |
370 | | bool validate(Json::Value* invalid) const; |
371 | | |
372 | | /** A simple way to update a specific setting. |
373 | | */ |
374 | | Value& operator[](const String& key); |
375 | | |
376 | | /** Called by ctor, but you can use this to reset settings_. |
377 | | * \pre 'settings' != NULL (but Json::null is fine) |
378 | | * \remark Defaults: |
379 | | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults |
380 | | */ |
381 | | static void setDefaults(Json::Value* settings); |
382 | | /** Same as old Features::strictMode(). |
383 | | * \pre 'settings' != NULL (but Json::null is fine) |
384 | | * \remark Defaults: |
385 | | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode |
386 | | */ |
387 | | static void strictMode(Json::Value* settings); |
388 | | /** ECMA-404 mode. |
389 | | * \pre 'settings' != NULL (but Json::null is fine) |
390 | | * \remark Defaults: |
391 | | * \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode |
392 | | */ |
393 | | static void ecma404Mode(Json::Value* settings); |
394 | | }; |
395 | | |
396 | | /** Consume entire stream and use its begin/end. |
397 | | * Someday we might have a real StreamReader, but for now this |
398 | | * is convenient. |
399 | | */ |
400 | | bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root, |
401 | | String* errs); |
402 | | |
403 | | /** \brief Read from 'sin' into 'root'. |
404 | | * |
405 | | * Always keep comments from the input JSON. |
406 | | * |
407 | | * This can be used to read a file into a particular sub-object. |
408 | | * For example: |
409 | | * \code |
410 | | * Json::Value root; |
411 | | * cin >> root["dir"]["file"]; |
412 | | * cout << root; |
413 | | * \endcode |
414 | | * Result: |
415 | | * \verbatim |
416 | | * { |
417 | | * "dir": { |
418 | | * "file": { |
419 | | * // The input stream JSON would be nested here. |
420 | | * } |
421 | | * } |
422 | | * } |
423 | | * \endverbatim |
424 | | * \throw std::exception on parse error. |
425 | | * \see Json::operator<<() |
426 | | */ |
427 | | JSON_API IStream& operator>>(IStream&, Value&); |
428 | | |
429 | | } // namespace Json |
430 | | |
431 | | #pragma pack(pop) |
432 | | |
433 | | #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) |
434 | | #pragma warning(pop) |
435 | | #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) |
436 | | |
437 | | #endif // JSON_READER_H_INCLUDED |