xref: /aosp_15_r20/external/jsoncpp/include/json/reader.h (revision 4484440890e2bc6e07362b4feaf15601abfe0071)
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 
28 namespace 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 
36 class JSON_API Reader {
37 public:
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 
157 private:
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  */
244 class JSON_API CharReader {
245 public:
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  */
288 class JSON_API CharReaderBuilder : public CharReader::Factory {
289 public:
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  */
368 bool 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  */
395 JSON_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