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 #if !defined(__SUNPRO_CC)
27 #pragma pack(push, 8)
28 #endif
29 
30 namespace Json {
31 
32 /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
33  * Value.
34  *
35  * deprecated Use CharReader and CharReaderBuilder.
36  */
37 
38 class JSONCPP_DEPRECATED(
39     "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
40 public:
41   using Char = char;
42   using Location = const Char*;
43 
44   /** \brief An error tagged with where in the JSON text it was encountered.
45    *
46    * The offsets give the [start, limit) range of bytes within the text. Note
47    * that this is bytes, not codepoints.
48    */
49   struct StructuredError {
50     ptrdiff_t offset_start;
51     ptrdiff_t offset_limit;
52     String message;
53   };
54 
55   /** \brief Constructs a Reader allowing all features for parsing.
56    */
57   JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
58   Reader();
59 
60   /** \brief Constructs a Reader allowing the specified feature set for parsing.
61    */
62   JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
63   Reader(const Features& features);
64 
65   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
66    * document.
67    *
68    * \param      document        UTF-8 encoded string containing the document
69    *                             to read.
70    * \param[out] root            Contains the root value of the document if it
71    *                             was successfully parsed.
72    * \param      collectComments \c true to collect comment and allow writing
73    *                             them back during serialization, \c false to
74    *                             discard comments.  This parameter is ignored
75    *                             if Features::allowComments_ is \c false.
76    * \return \c true if the document was successfully parsed, \c false if an
77    * error occurred.
78    */
79   bool parse(const std::string& document, Value& root,
80              bool collectComments = true);
81 
82   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
83    * document.
84    *
85    * \param      beginDoc        Pointer on the beginning of the UTF-8 encoded
86    *                             string of the document to read.
87    * \param      endDoc          Pointer on the end of the UTF-8 encoded string
88    *                             of the document to read.  Must be >= beginDoc.
89    * \param[out] root            Contains the root value of the document if it
90    *                             was successfully parsed.
91    * \param      collectComments \c true to collect comment and allow writing
92    *                             them back during serialization, \c false to
93    *                             discard comments.  This parameter is ignored
94    *                             if Features::allowComments_ is \c false.
95    * \return \c true if the document was successfully parsed, \c false if an
96    * error occurred.
97    */
98   bool parse(const char* beginDoc, const char* endDoc, Value& root,
99              bool collectComments = true);
100 
101   /// \brief Parse from input stream.
102   /// \see Json::operator>>(std::istream&, Json::Value&).
103   bool parse(IStream& is, Value& root, bool collectComments = true);
104 
105   /** \brief Returns a user friendly string that list errors in the parsed
106    * document.
107    *
108    * \return Formatted error message with the list of errors with their
109    * location in the parsed document. An empty string is returned if no error
110    * occurred during parsing.
111    * deprecated Use getFormattedErrorMessages() instead (typo fix).
112    */
113   JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
114   String getFormatedErrorMessages() const;
115 
116   /** \brief Returns a user friendly string that list errors in the parsed
117    * document.
118    *
119    * \return Formatted error message with the list of errors with their
120    * location in the parsed document. An empty string is returned if no error
121    * occurred during parsing.
122    */
123   String getFormattedErrorMessages() const;
124 
125   /** \brief Returns a vector of structured errors encountered while parsing.
126    *
127    * \return A (possibly empty) vector of StructuredError objects. Currently
128    * only one error can be returned, but the caller should tolerate multiple
129    * errors.  This can occur if the parser recovers from a non-fatal parse
130    * error and then encounters additional errors.
131    */
132   std::vector<StructuredError> getStructuredErrors() const;
133 
134   /** \brief Add a semantic error message.
135    *
136    * \param value   JSON Value location associated with the error
137    * \param message The error message.
138    * \return \c true if the error was successfully added, \c false if the Value
139    * offset exceeds the document size.
140    */
141   bool pushError(const Value& value, const String& message);
142 
143   /** \brief Add a semantic error message with extra context.
144    *
145    * \param value   JSON Value location associated with the error
146    * \param message The error message.
147    * \param extra   Additional JSON Value location to contextualize the error
148    * \return \c true if the error was successfully added, \c false if either
149    * Value offset exceeds the document size.
150    */
151   bool pushError(const Value& value, const String& message, const Value& extra);
152 
153   /** \brief Return whether there are any errors.
154    *
155    * \return \c true if there are no errors to report \c false if errors have
156    * occurred.
157    */
158   bool good() const;
159 
160 private:
161   enum TokenType {
162     tokenEndOfStream = 0,
163     tokenObjectBegin,
164     tokenObjectEnd,
165     tokenArrayBegin,
166     tokenArrayEnd,
167     tokenString,
168     tokenNumber,
169     tokenTrue,
170     tokenFalse,
171     tokenNull,
172     tokenArraySeparator,
173     tokenMemberSeparator,
174     tokenComment,
175     tokenError
176   };
177 
178   class Token {
179   public:
180     TokenType type_;
181     Location start_;
182     Location end_;
183   };
184 
185   class ErrorInfo {
186   public:
187     Token token_;
188     String message_;
189     Location extra_;
190   };
191 
192   using Errors = std::deque<ErrorInfo>;
193 
194   bool readToken(Token& token);
195   void skipSpaces();
196   bool match(const Char* pattern, int patternLength);
197   bool readComment();
198   bool readCStyleComment();
199   bool readCppStyleComment();
200   bool readString();
201   void readNumber();
202   bool readValue();
203   bool readObject(Token& token);
204   bool readArray(Token& token);
205   bool decodeNumber(Token& token);
206   bool decodeNumber(Token& token, Value& decoded);
207   bool decodeString(Token& token);
208   bool decodeString(Token& token, String& decoded);
209   bool decodeDouble(Token& token);
210   bool decodeDouble(Token& token, Value& decoded);
211   bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
212                               unsigned int& unicode);
213   bool decodeUnicodeEscapeSequence(Token& token, Location& current,
214                                    Location end, unsigned int& unicode);
215   bool addError(const String& message, Token& token, Location extra = nullptr);
216   bool recoverFromError(TokenType skipUntilToken);
217   bool addErrorAndRecover(const String& message, Token& token,
218                           TokenType skipUntilToken);
219   void skipUntilSpace();
220   Value& currentValue();
221   Char getNextChar();
222   void getLocationLineAndColumn(Location location, int& line,
223                                 int& column) const;
224   String getLocationLineAndColumn(Location location) const;
225   void addComment(Location begin, Location end, CommentPlacement placement);
226   void skipCommentTokens(Token& token);
227 
228   static bool containsNewLine(Location begin, Location end);
229   static String normalizeEOL(Location begin, Location end);
230 
231   using Nodes = std::stack<Value*>;
232   Nodes nodes_;
233   Errors errors_;
234   String document_;
235   Location begin_{};
236   Location end_{};
237   Location current_{};
238   Location lastValueEnd_{};
239   Value* lastValue_{};
240   String commentsBefore_;
241   Features features_;
242   bool collectComments_{};
243 }; // Reader
244 
245 /** Interface for reading JSON from a char array.
246  */
247 class JSON_API CharReader {
248 public:
249   virtual ~CharReader() = default;
250   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
251    * document. The document must be a UTF-8 encoded string containing the
252    * document to read.
253    *
254    * \param      beginDoc Pointer on the beginning of the UTF-8 encoded string
255    *                      of the document to read.
256    * \param      endDoc   Pointer on the end of the UTF-8 encoded string of the
257    *                      document to read. Must be >= beginDoc.
258    * \param[out] root     Contains the root value of the document if it was
259    *                      successfully parsed.
260    * \param[out] errs     Formatted error messages (if not NULL) a user
261    *                      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(char const* beginDoc, char const* endDoc, Value* root,
267                      String* errs) = 0;
268 
269   class JSON_API Factory {
270   public:
271     virtual ~Factory() = default;
272     /** \brief Allocate a CharReader via operator new().
273      * \throw std::exception if something goes wrong (e.g. invalid settings)
274      */
275     virtual CharReader* newCharReader() const = 0;
276   }; // Factory
277 };   // CharReader
278 
279 /** \brief Build a CharReader implementation.
280  *
281  * Usage:
282  *   \code
283  *   using namespace Json;
284  *   CharReaderBuilder builder;
285  *   builder["collectComments"] = false;
286  *   Value value;
287  *   String errs;
288  *   bool ok = parseFromStream(builder, std::cin, &value, &errs);
289  *   \endcode
290  */
291 class JSON_API CharReaderBuilder : public CharReader::Factory {
292 public:
293   // Note: We use a Json::Value so that we can add data-members to this class
294   // without a major version bump.
295   /** Configuration of this builder.
296    * These are case-sensitive.
297    * Available settings (case-sensitive):
298    * - `"collectComments": false or true`
299    *   - true to collect comment and allow writing them back during
300    *     serialization, false to discard comments.  This parameter is ignored
301    *     if allowComments is false.
302    * - `"allowComments": false or true`
303    *   - true if comments are allowed.
304    * - `"allowTrailingCommas": false or true`
305    *   - true if trailing commas in objects and arrays are allowed.
306    * - `"strictRoot": false or true`
307    *   - true if root must be either an array or an object value
308    * - `"allowDroppedNullPlaceholders": false or true`
309    *   - true if dropped null placeholders are allowed. (See
310    *     StreamWriterBuilder.)
311    * - `"allowNumericKeys": false or true`
312    *   - true if numeric object keys are allowed.
313    * - `"allowSingleQuotes": false or true`
314    *   - true if '' are allowed for strings (both keys and values)
315    * - `"stackLimit": integer`
316    *   - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
317    *     exception.
318    *   - This is a security issue (seg-faults caused by deeply nested JSON), so
319    *     the default is low.
320    * - `"failIfExtra": false or true`
321    *   - If true, `parse()` returns false when extra non-whitespace trails the
322    *     JSON value in the input string.
323    * - `"rejectDupKeys": false or true`
324    *   - If true, `parse()` returns false when a key is duplicated within an
325    *     object.
326    * - `"allowSpecialFloats": false or true`
327    *   - If true, special float values (NaNs and infinities) are allowed and
328    *     their values are lossfree restorable.
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 #if !defined(__SUNPRO_CC)
400 #pragma pack(pop)
401 #endif
402 
403 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
404 #pragma warning(pop)
405 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
406 
407 #endif // JSON_READER_H_INCLUDED
408