404 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			404 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
 | 
						|
// Distributed under MIT license, or public domain if desired and
 | 
						|
// recognized in your jurisdiction.
 | 
						|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 | 
						|
 | 
						|
#ifndef JSON_READER_H_INCLUDED
 | 
						|
#define JSON_READER_H_INCLUDED
 | 
						|
 | 
						|
#if !defined(JSON_IS_AMALGAMATION)
 | 
						|
#include "json_features.h"
 | 
						|
#include "value.h"
 | 
						|
#endif // if !defined(JSON_IS_AMALGAMATION)
 | 
						|
#include <deque>
 | 
						|
#include <iosfwd>
 | 
						|
#include <istream>
 | 
						|
#include <stack>
 | 
						|
#include <string>
 | 
						|
 | 
						|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
 | 
						|
// be used by...
 | 
						|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
 | 
						|
#pragma warning(push)
 | 
						|
#pragma warning(disable : 4251)
 | 
						|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
 | 
						|
 | 
						|
#pragma pack(push, 8)
 | 
						|
 | 
						|
namespace Json {
 | 
						|
 | 
						|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
 | 
						|
 * Value.
 | 
						|
 *
 | 
						|
 * \deprecated Use CharReader and CharReaderBuilder.
 | 
						|
 */
 | 
						|
 | 
						|
class JSONCPP_DEPRECATED(
 | 
						|
    "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
 | 
						|
public:
 | 
						|
  using Char = char;
 | 
						|
  using Location = const Char*;
 | 
						|
 | 
						|
  /** \brief An error tagged with where in the JSON text it was encountered.
 | 
						|
   *
 | 
						|
   * The offsets give the [start, limit) range of bytes within the text. Note
 | 
						|
   * that this is bytes, not codepoints.
 | 
						|
   */
 | 
						|
  struct StructuredError {
 | 
						|
    ptrdiff_t offset_start;
 | 
						|
    ptrdiff_t offset_limit;
 | 
						|
    String message;
 | 
						|
  };
 | 
						|
 | 
						|
  /** \brief Constructs a Reader allowing all features for parsing.
 | 
						|
   */
 | 
						|
  JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
 | 
						|
  Reader();
 | 
						|
 | 
						|
  /** \brief Constructs a Reader allowing the specified feature set for parsing.
 | 
						|
   */
 | 
						|
  JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
 | 
						|
  Reader(const Features& features);
 | 
						|
 | 
						|
  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
 | 
						|
   * document.
 | 
						|
   *
 | 
						|
   * \param      document        UTF-8 encoded string containing the document
 | 
						|
   *                             to read.
 | 
						|
   * \param[out] root            Contains the root value of the document if it
 | 
						|
   *                             was successfully parsed.
 | 
						|
   * \param      collectComments \c true to collect comment and allow writing
 | 
						|
   *                             them back during serialization, \c false to
 | 
						|
   *                             discard comments.  This parameter is ignored
 | 
						|
   *                             if Features::allowComments_ is \c false.
 | 
						|
   * \return \c true if the document was successfully parsed, \c false if an
 | 
						|
   * error occurred.
 | 
						|
   */
 | 
						|
  bool parse(const std::string& document, Value& root,
 | 
						|
             bool collectComments = true);
 | 
						|
 | 
						|
  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
 | 
						|
   * document.
 | 
						|
   *
 | 
						|
   * \param      beginDoc        Pointer on the beginning of the UTF-8 encoded
 | 
						|
   *                             string of the document to read.
 | 
						|
   * \param      endDoc          Pointer on the end of the UTF-8 encoded string
 | 
						|
   *                             of the document to read.  Must be >= beginDoc.
 | 
						|
   * \param[out] root            Contains the root value of the document if it
 | 
						|
   *                             was successfully parsed.
 | 
						|
   * \param      collectComments \c true to collect comment and allow writing
 | 
						|
   *                             them back during serialization, \c false to
 | 
						|
   *                             discard comments.  This parameter is ignored
 | 
						|
   *                             if Features::allowComments_ is \c false.
 | 
						|
   * \return \c true if the document was successfully parsed, \c false if an
 | 
						|
   * error occurred.
 | 
						|
   */
 | 
						|
  bool parse(const char* beginDoc, const char* endDoc, Value& root,
 | 
						|
             bool collectComments = true);
 | 
						|
 | 
						|
  /// \brief Parse from input stream.
 | 
						|
  /// \see Json::operator>>(std::istream&, Json::Value&).
 | 
						|
  bool parse(IStream& is, Value& root, bool collectComments = true);
 | 
						|
 | 
						|
  /** \brief Returns a user friendly string that list errors in the parsed
 | 
						|
   * document.
 | 
						|
   *
 | 
						|
   * \return Formatted error message with the list of errors with their
 | 
						|
   * location in the parsed document. An empty string is returned if no error
 | 
						|
   * occurred during parsing.
 | 
						|
   * \deprecated Use getFormattedErrorMessages() instead (typo fix).
 | 
						|
   */
 | 
						|
  JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
 | 
						|
  String getFormatedErrorMessages() const;
 | 
						|
 | 
						|
  /** \brief Returns a user friendly string that list errors in the parsed
 | 
						|
   * document.
 | 
						|
   *
 | 
						|
   * \return Formatted error message with the list of errors with their
 | 
						|
   * location in the parsed document. An empty string is returned if no error
 | 
						|
   * occurred during parsing.
 | 
						|
   */
 | 
						|
  String getFormattedErrorMessages() const;
 | 
						|
 | 
						|
  /** \brief Returns a vector of structured errors encountered while parsing.
 | 
						|
   *
 | 
						|
   * \return A (possibly empty) vector of StructuredError objects. Currently
 | 
						|
   * only one error can be returned, but the caller should tolerate multiple
 | 
						|
   * errors.  This can occur if the parser recovers from a non-fatal parse
 | 
						|
   * error and then encounters additional errors.
 | 
						|
   */
 | 
						|
  std::vector<StructuredError> getStructuredErrors() const;
 | 
						|
 | 
						|
  /** \brief Add a semantic error message.
 | 
						|
   *
 | 
						|
   * \param value   JSON Value location associated with the error
 | 
						|
   * \param message The error message.
 | 
						|
   * \return \c true if the error was successfully added, \c false if the Value
 | 
						|
   * offset exceeds the document size.
 | 
						|
   */
 | 
						|
  bool pushError(const Value& value, const String& message);
 | 
						|
 | 
						|
  /** \brief Add a semantic error message with extra context.
 | 
						|
   *
 | 
						|
   * \param value   JSON Value location associated with the error
 | 
						|
   * \param message The error message.
 | 
						|
   * \param extra   Additional JSON Value location to contextualize the error
 | 
						|
   * \return \c true if the error was successfully added, \c false if either
 | 
						|
   * Value offset exceeds the document size.
 | 
						|
   */
 | 
						|
  bool pushError(const Value& value, const String& message, const Value& extra);
 | 
						|
 | 
						|
  /** \brief Return whether there are any errors.
 | 
						|
   *
 | 
						|
   * \return \c true if there are no errors to report \c false if errors have
 | 
						|
   * occurred.
 | 
						|
   */
 | 
						|
  bool good() const;
 | 
						|
 | 
						|
private:
 | 
						|
  enum TokenType {
 | 
						|
    tokenEndOfStream = 0,
 | 
						|
    tokenObjectBegin,
 | 
						|
    tokenObjectEnd,
 | 
						|
    tokenArrayBegin,
 | 
						|
    tokenArrayEnd,
 | 
						|
    tokenString,
 | 
						|
    tokenNumber,
 | 
						|
    tokenTrue,
 | 
						|
    tokenFalse,
 | 
						|
    tokenNull,
 | 
						|
    tokenArraySeparator,
 | 
						|
    tokenMemberSeparator,
 | 
						|
    tokenComment,
 | 
						|
    tokenError
 | 
						|
  };
 | 
						|
 | 
						|
  class Token {
 | 
						|
  public:
 | 
						|
    TokenType type_;
 | 
						|
    Location start_;
 | 
						|
    Location end_;
 | 
						|
  };
 | 
						|
 | 
						|
  class ErrorInfo {
 | 
						|
  public:
 | 
						|
    Token token_;
 | 
						|
    String message_;
 | 
						|
    Location extra_;
 | 
						|
  };
 | 
						|
 | 
						|
  using Errors = std::deque<ErrorInfo>;
 | 
						|
 | 
						|
  bool readToken(Token& token);
 | 
						|
  void skipSpaces();
 | 
						|
  bool match(const Char* pattern, int patternLength);
 | 
						|
  bool readComment();
 | 
						|
  bool readCStyleComment();
 | 
						|
  bool readCppStyleComment();
 | 
						|
  bool readString();
 | 
						|
  void readNumber();
 | 
						|
  bool readValue();
 | 
						|
  bool readObject(Token& token);
 | 
						|
  bool readArray(Token& token);
 | 
						|
  bool decodeNumber(Token& token);
 | 
						|
  bool decodeNumber(Token& token, Value& decoded);
 | 
						|
  bool decodeString(Token& token);
 | 
						|
  bool decodeString(Token& token, String& decoded);
 | 
						|
  bool decodeDouble(Token& token);
 | 
						|
  bool decodeDouble(Token& token, Value& decoded);
 | 
						|
  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
 | 
						|
                              unsigned int& unicode);
 | 
						|
  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
 | 
						|
                                   Location end, unsigned int& unicode);
 | 
						|
  bool addError(const String& message, Token& token, Location extra = nullptr);
 | 
						|
  bool recoverFromError(TokenType skipUntilToken);
 | 
						|
  bool addErrorAndRecover(const String& message, Token& token,
 | 
						|
                          TokenType skipUntilToken);
 | 
						|
  void skipUntilSpace();
 | 
						|
  Value& currentValue();
 | 
						|
  Char getNextChar();
 | 
						|
  void getLocationLineAndColumn(Location location, int& line,
 | 
						|
                                int& column) const;
 | 
						|
  String getLocationLineAndColumn(Location location) const;
 | 
						|
  void addComment(Location begin, Location end, CommentPlacement placement);
 | 
						|
  void skipCommentTokens(Token& token);
 | 
						|
 | 
						|
  static bool containsNewLine(Location begin, Location end);
 | 
						|
  static String normalizeEOL(Location begin, Location end);
 | 
						|
 | 
						|
  using Nodes = std::stack<Value*>;
 | 
						|
  Nodes nodes_;
 | 
						|
  Errors errors_;
 | 
						|
  String document_;
 | 
						|
  Location begin_{};
 | 
						|
  Location end_{};
 | 
						|
  Location current_{};
 | 
						|
  Location lastValueEnd_{};
 | 
						|
  Value* lastValue_{};
 | 
						|
  String commentsBefore_;
 | 
						|
  Features features_;
 | 
						|
  bool collectComments_{};
 | 
						|
}; // Reader
 | 
						|
 | 
						|
/** Interface for reading JSON from a char array.
 | 
						|
 */
 | 
						|
class JSON_API CharReader {
 | 
						|
public:
 | 
						|
  virtual ~CharReader() = default;
 | 
						|
  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
 | 
						|
   * document. The document must be a UTF-8 encoded string containing the
 | 
						|
   * document to read.
 | 
						|
   *
 | 
						|
   * \param      beginDoc Pointer on the beginning of the UTF-8 encoded string
 | 
						|
   *                      of the document to read.
 | 
						|
   * \param      endDoc   Pointer on the end of the UTF-8 encoded string of the
 | 
						|
   *                      document to read. Must be >= beginDoc.
 | 
						|
   * \param[out] root     Contains the root value of the document if it was
 | 
						|
   *                      successfully parsed.
 | 
						|
   * \param[out] errs     Formatted error messages (if not NULL) a user
 | 
						|
   *                      friendly string that lists errors in the parsed
 | 
						|
   *                      document.
 | 
						|
   * \return \c true if the document was successfully parsed, \c false if an
 | 
						|
   * error occurred.
 | 
						|
   */
 | 
						|
  virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
 | 
						|
                     String* errs) = 0;
 | 
						|
 | 
						|
  class JSON_API Factory {
 | 
						|
  public:
 | 
						|
    virtual ~Factory() = default;
 | 
						|
    /** \brief Allocate a CharReader via operator new().
 | 
						|
     * \throw std::exception if something goes wrong (e.g. invalid settings)
 | 
						|
     */
 | 
						|
    virtual CharReader* newCharReader() const = 0;
 | 
						|
  }; // Factory
 | 
						|
};   // CharReader
 | 
						|
 | 
						|
/** \brief Build a CharReader implementation.
 | 
						|
 *
 | 
						|
 * Usage:
 | 
						|
 *   \code
 | 
						|
 *   using namespace Json;
 | 
						|
 *   CharReaderBuilder builder;
 | 
						|
 *   builder["collectComments"] = false;
 | 
						|
 *   Value value;
 | 
						|
 *   String errs;
 | 
						|
 *   bool ok = parseFromStream(builder, std::cin, &value, &errs);
 | 
						|
 *   \endcode
 | 
						|
 */
 | 
						|
class JSON_API CharReaderBuilder : public CharReader::Factory {
 | 
						|
public:
 | 
						|
  // Note: We use a Json::Value so that we can add data-members to this class
 | 
						|
  // without a major version bump.
 | 
						|
  /** Configuration of this builder.
 | 
						|
   * These are case-sensitive.
 | 
						|
   * Available settings (case-sensitive):
 | 
						|
   * - `"collectComments": false or true`
 | 
						|
   *   - true to collect comment and allow writing them back during
 | 
						|
   *     serialization, false to discard comments.  This parameter is ignored
 | 
						|
   *     if allowComments is false.
 | 
						|
   * - `"allowComments": false or true`
 | 
						|
   *   - true if comments are allowed.
 | 
						|
   * - `"allowTrailingCommas": false or true`
 | 
						|
   *   - true if trailing commas in objects and arrays are allowed.
 | 
						|
   * - `"strictRoot": false or true`
 | 
						|
   *   - true if root must be either an array or an object value
 | 
						|
   * - `"allowDroppedNullPlaceholders": false or true`
 | 
						|
   *   - true if dropped null placeholders are allowed. (See
 | 
						|
   *     StreamWriterBuilder.)
 | 
						|
   * - `"allowNumericKeys": false or true`
 | 
						|
   *   - true if numeric object keys are allowed.
 | 
						|
   * - `"allowSingleQuotes": false or true`
 | 
						|
   *   - true if '' are allowed for strings (both keys and values)
 | 
						|
   * - `"stackLimit": integer`
 | 
						|
   *   - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
 | 
						|
   *     exception.
 | 
						|
   *   - This is a security issue (seg-faults caused by deeply nested JSON), so
 | 
						|
   *     the default is low.
 | 
						|
   * - `"failIfExtra": false or true`
 | 
						|
   *   - If true, `parse()` returns false when extra non-whitespace trails the
 | 
						|
   *     JSON value in the input string.
 | 
						|
   * - `"rejectDupKeys": false or true`
 | 
						|
   *   - If true, `parse()` returns false when a key is duplicated within an
 | 
						|
   *     object.
 | 
						|
   * - `"allowSpecialFloats": false or true`
 | 
						|
   *   - If true, special float values (NaNs and infinities) are allowed and
 | 
						|
   *     their values are lossfree restorable.
 | 
						|
   *
 | 
						|
   * You can examine 'settings_` yourself to see the defaults. You can also
 | 
						|
   * write and read them just like any JSON Value.
 | 
						|
   * \sa setDefaults()
 | 
						|
   */
 | 
						|
  Json::Value settings_;
 | 
						|
 | 
						|
  CharReaderBuilder();
 | 
						|
  ~CharReaderBuilder() override;
 | 
						|
 | 
						|
  CharReader* newCharReader() const override;
 | 
						|
 | 
						|
  /** \return true if 'settings' are legal and consistent;
 | 
						|
   *   otherwise, indicate bad settings via 'invalid'.
 | 
						|
   */
 | 
						|
  bool validate(Json::Value* invalid) const;
 | 
						|
 | 
						|
  /** A simple way to update a specific setting.
 | 
						|
   */
 | 
						|
  Value& operator[](const String& key);
 | 
						|
 | 
						|
  /** Called by ctor, but you can use this to reset settings_.
 | 
						|
   * \pre 'settings' != NULL (but Json::null is fine)
 | 
						|
   * \remark Defaults:
 | 
						|
   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
 | 
						|
   */
 | 
						|
  static void setDefaults(Json::Value* settings);
 | 
						|
  /** Same as old Features::strictMode().
 | 
						|
   * \pre 'settings' != NULL (but Json::null is fine)
 | 
						|
   * \remark Defaults:
 | 
						|
   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
 | 
						|
   */
 | 
						|
  static void strictMode(Json::Value* settings);
 | 
						|
};
 | 
						|
 | 
						|
/** Consume entire stream and use its begin/end.
 | 
						|
 * Someday we might have a real StreamReader, but for now this
 | 
						|
 * is convenient.
 | 
						|
 */
 | 
						|
bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
 | 
						|
                              String* errs);
 | 
						|
 | 
						|
/** \brief Read from 'sin' into 'root'.
 | 
						|
 *
 | 
						|
 * Always keep comments from the input JSON.
 | 
						|
 *
 | 
						|
 * This can be used to read a file into a particular sub-object.
 | 
						|
 * For example:
 | 
						|
 *   \code
 | 
						|
 *   Json::Value root;
 | 
						|
 *   cin >> root["dir"]["file"];
 | 
						|
 *   cout << root;
 | 
						|
 *   \endcode
 | 
						|
 * Result:
 | 
						|
 * \verbatim
 | 
						|
 * {
 | 
						|
 * "dir": {
 | 
						|
 *    "file": {
 | 
						|
 *    // The input stream JSON would be nested here.
 | 
						|
 *    }
 | 
						|
 * }
 | 
						|
 * }
 | 
						|
 * \endverbatim
 | 
						|
 * \throw std::exception on parse error.
 | 
						|
 * \see Json::operator<<()
 | 
						|
 */
 | 
						|
JSON_API IStream& operator>>(IStream&, Value&);
 | 
						|
 | 
						|
} // namespace Json
 | 
						|
 | 
						|
#pragma pack(pop)
 | 
						|
 | 
						|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
 | 
						|
#pragma warning(pop)
 | 
						|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
 | 
						|
 | 
						|
#endif // JSON_READER_H_INCLUDED
 |