Home | History | Annotate | Download | only in json
      1 // Copyright 2007-2010 Baptiste Lepilleur
      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 <stack>
     16 #include <string>
     17 
     18 // Disable warning C4251: <data member>: <type> needs to have dll-interface to
     19 // be used by...
     20 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
     21 #pragma warning(push)
     22 #pragma warning(disable : 4251)
     23 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
     24 
     25 namespace Json {
     26 
     27 /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
     28  *Value.
     29  *
     30  */
     31 class JSON_API Reader {
     32 public:
     33   typedef char Char;
     34   typedef const Char* Location;
     35 
     36   /** \brief An error tagged with where in the JSON text it was encountered.
     37    *
     38    * The offsets give the [start, limit) range of bytes within the text. Note
     39    * that this is bytes, not codepoints.
     40    *
     41    */
     42   struct StructuredError {
     43     size_t offset_start;
     44     size_t offset_limit;
     45     std::string message;
     46   };
     47 
     48   /** \brief Constructs a Reader allowing all features
     49    * for parsing.
     50    */
     51   Reader();
     52 
     53   /** \brief Constructs a Reader allowing the specified feature set
     54    * for parsing.
     55    */
     56   Reader(const Features& features);
     57 
     58   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
     59    * document.
     60    * \param document UTF-8 encoded string containing the document to read.
     61    * \param root [out] Contains the root value of the document if it was
     62    *             successfully parsed.
     63    * \param collectComments \c true to collect comment and allow writing them
     64    * back during
     65    *                        serialization, \c false to discard comments.
     66    *                        This parameter is ignored if
     67    * Features::allowComments_
     68    *                        is \c false.
     69    * \return \c true if the document was successfully parsed, \c false if an
     70    * error occurred.
     71    */
     72   bool
     73   parse(const std::string& document, Value& root, bool collectComments = true);
     74 
     75   /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
     76    document.
     77    * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
     78    document to read.
     79    * \param endDoc Pointer on the end of the UTF-8 encoded string of the
     80    document to read.
     81    \               Must be >= beginDoc.
     82    * \param root [out] Contains the root value of the document if it was
     83    *             successfully parsed.
     84    * \param collectComments \c true to collect comment and allow writing them
     85    back during
     86    *                        serialization, \c false to discard comments.
     87    *                        This parameter is ignored if
     88    Features::allowComments_
     89    *                        is \c false.
     90    * \return \c true if the document was successfully parsed, \c false if an
     91    error occurred.
     92    */
     93   bool parse(const char* beginDoc,
     94              const char* endDoc,
     95              Value& root,
     96              bool collectComments = true);
     97 
     98   /// \brief Parse from input stream.
     99   /// \see Json::operator>>(std::istream&, Json::Value&).
    100   bool parse(std::istream& is, Value& root, bool collectComments = true);
    101 
    102   /** \brief Returns a user friendly string that list errors in the parsed
    103    * document.
    104    * \return Formatted error message with the list of errors with their location
    105    * in
    106    *         the parsed document. An empty string is returned if no error
    107    * occurred
    108    *         during parsing.
    109    * \deprecated Use getFormattedErrorMessages() instead (typo fix).
    110    */
    111   JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
    112   std::string getFormatedErrorMessages() const;
    113 
    114   /** \brief Returns a user friendly string that list errors in the parsed
    115    * document.
    116    * \return Formatted error message with the list of errors with their location
    117    * in
    118    *         the parsed document. An empty string is returned if no error
    119    * occurred
    120    *         during parsing.
    121    */
    122   std::string getFormattedErrorMessages() const;
    123 
    124   /** \brief Returns a vector of structured erros encounted while parsing.
    125    * \return A (possibly empty) vector of StructuredError objects. Currently
    126    *         only one error can be returned, but the caller should tolerate
    127    * multiple
    128    *         errors.  This can occur if the parser recovers from a non-fatal
    129    *         parse error and then encounters additional errors.
    130    */
    131   std::vector<StructuredError> getStructuredErrors() const;
    132 
    133   /** \brief Add a semantic error message.
    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
    137    * Value offset exceeds the document size.
    138    */
    139   bool pushError(const Value& value, const std::string& message);
    140 
    141   /** \brief Add a semantic error message with extra context.
    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 std::string& message, const Value& extra);
    149 
    150   /** \brief Return whether there are any errors.
    151    * \return \c true if there are no errors to report \c false if
    152    * errors have occurred.
    153    */
    154   bool good() const;
    155 
    156 private:
    157   enum TokenType {
    158     tokenEndOfStream = 0,
    159     tokenObjectBegin,
    160     tokenObjectEnd,
    161     tokenArrayBegin,
    162     tokenArrayEnd,
    163     tokenString,
    164     tokenNumber,
    165     tokenTrue,
    166     tokenFalse,
    167     tokenNull,
    168     tokenArraySeparator,
    169     tokenMemberSeparator,
    170     tokenComment,
    171     tokenError
    172   };
    173 
    174   class Token {
    175   public:
    176     TokenType type_;
    177     Location start_;
    178     Location end_;
    179   };
    180 
    181   class ErrorInfo {
    182   public:
    183     Token token_;
    184     std::string message_;
    185     Location extra_;
    186   };
    187 
    188   typedef std::deque<ErrorInfo> Errors;
    189 
    190   bool expectToken(TokenType type, Token& token, const char* message);
    191   bool readToken(Token& token);
    192   void skipSpaces();
    193   bool match(Location 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, std::string& decoded);
    206   bool decodeDouble(Token& token);
    207   bool decodeDouble(Token& token, Value& decoded);
    208   bool decodeUnicodeCodePoint(Token& token,
    209                               Location& current,
    210                               Location end,
    211                               unsigned int& unicode);
    212   bool decodeUnicodeEscapeSequence(Token& token,
    213                                    Location& current,
    214                                    Location end,
    215                                    unsigned int& unicode);
    216   bool addError(const std::string& message, Token& token, Location extra = 0);
    217   bool recoverFromError(TokenType skipUntilToken);
    218   bool addErrorAndRecover(const std::string& message,
    219                           Token& token,
    220                           TokenType skipUntilToken);
    221   void skipUntilSpace();
    222   Value& currentValue();
    223   Char getNextChar();
    224   void
    225   getLocationLineAndColumn(Location location, int& line, int& column) const;
    226   std::string getLocationLineAndColumn(Location location) const;
    227   void addComment(Location begin, Location end, CommentPlacement placement);
    228   void skipCommentTokens(Token& token);
    229 
    230   typedef std::stack<Value*> Nodes;
    231   Nodes nodes_;
    232   Errors errors_;
    233   std::string document_;
    234   Location begin_;
    235   Location end_;
    236   Location current_;
    237   Location lastValueEnd_;
    238   Value* lastValue_;
    239   std::string commentsBefore_;
    240   Features features_;
    241   bool collectComments_;
    242 };
    243 
    244 /** \brief Read from 'sin' into 'root'.
    245 
    246  Always keep comments from the input JSON.
    247 
    248  This can be used to read a file into a particular sub-object.
    249  For example:
    250  \code
    251  Json::Value root;
    252  cin >> root["dir"]["file"];
    253  cout << root;
    254  \endcode
    255  Result:
    256  \verbatim
    257  {
    258  "dir": {
    259      "file": {
    260      // The input stream JSON would be nested here.
    261      }
    262  }
    263  }
    264  \endverbatim
    265  \throw std::exception on parse error.
    266  \see Json::operator<<()
    267 */
    268 JSON_API std::istream& operator>>(std::istream&, Value&);
    269 
    270 } // namespace Json
    271 
    272 #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
    273 #pragma warning(pop)
    274 #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
    275 
    276 #endif // CPPTL_JSON_READER_H_INCLUDED
    277