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