Path: blob/master/Utilities/cmjsoncpp/include/json/reader.h
3156 views
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors1// Distributed under MIT license, or public domain if desired and2// recognized in your jurisdiction.3// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE45#ifndef JSON_READER_H_INCLUDED6#define JSON_READER_H_INCLUDED78#if !defined(JSON_IS_AMALGAMATION)9#include "json_features.h"10#include "value.h"11#endif // if !defined(JSON_IS_AMALGAMATION)12#include <deque>13#include <iosfwd>14#include <istream>15#include <stack>16#include <string>1718// Disable warning C4251: <data member>: <type> needs to have dll-interface to19// 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)2425#if !defined(__SUNPRO_CC)26#pragma pack(push)27#pragma pack()28#endif2930namespace Json {3132/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a33* Value.34*35* deprecated Use CharReader and CharReaderBuilder.36*/3738class JSON_API Reader {39public:40using Char = char;41using Location = const Char*;4243/** \brief An error tagged with where in the JSON text it was encountered.44*45* The offsets give the [start, limit) range of bytes within the text. Note46* that this is bytes, not codepoints.47*/48struct StructuredError {49ptrdiff_t offset_start;50ptrdiff_t offset_limit;51String message;52};5354/** \brief Constructs a Reader allowing all features for parsing.55* deprecated Use CharReader and CharReaderBuilder.56*/57Reader();5859/** \brief Constructs a Reader allowing the specified feature set for parsing.60* deprecated Use CharReader and CharReaderBuilder.61*/62Reader(const Features& features);6364/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>65* document.66*67* \param document UTF-8 encoded string containing the document68* to read.69* \param[out] root Contains the root value of the document if it70* was successfully parsed.71* \param collectComments \c true to collect comment and allow writing72* them back during serialization, \c false to73* discard comments. This parameter is ignored74* if Features::allowComments_ is \c false.75* \return \c true if the document was successfully parsed, \c false if an76* error occurred.77*/78bool parse(const std::string& document, Value& root,79bool collectComments = true);8081/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>82* document.83*84* \param beginDoc Pointer on the beginning of the UTF-8 encoded85* string of the document to read.86* \param endDoc Pointer on the end of the UTF-8 encoded string87* of the document to read. Must be >= beginDoc.88* \param[out] root Contains the root value of the document if it89* was successfully parsed.90* \param collectComments \c true to collect comment and allow writing91* them back during serialization, \c false to92* discard comments. This parameter is ignored93* if Features::allowComments_ is \c false.94* \return \c true if the document was successfully parsed, \c false if an95* error occurred.96*/97bool parse(const char* beginDoc, const char* endDoc, Value& root,98bool collectComments = true);99100/// \brief Parse from input stream.101/// \see Json::operator>>(std::istream&, Json::Value&).102bool parse(IStream& is, Value& root, bool collectComments = true);103104/** \brief Returns a user friendly string that list errors in the parsed105* document.106*107* \return Formatted error message with the list of errors with their108* location in the parsed document. An empty string is returned if no error109* occurred during parsing.110* deprecated Use getFormattedErrorMessages() instead (typo fix).111*/112JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")113String getFormatedErrorMessages() const;114115/** \brief Returns a user friendly string that list errors in the parsed116* document.117*118* \return Formatted error message with the list of errors with their119* location in the parsed document. An empty string is returned if no error120* occurred during parsing.121*/122String getFormattedErrorMessages() const;123124/** \brief Returns a vector of structured errors encountered while parsing.125*126* \return A (possibly empty) vector of StructuredError objects. Currently127* only one error can be returned, but the caller should tolerate multiple128* errors. This can occur if the parser recovers from a non-fatal parse129* error and then encounters additional errors.130*/131std::vector<StructuredError> getStructuredErrors() const;132133/** \brief Add a semantic error message.134*135* \param value JSON Value location associated with the error136* \param message The error message.137* \return \c true if the error was successfully added, \c false if the Value138* offset exceeds the document size.139*/140bool pushError(const Value& value, const String& message);141142/** \brief Add a semantic error message with extra context.143*144* \param value JSON Value location associated with the error145* \param message The error message.146* \param extra Additional JSON Value location to contextualize the error147* \return \c true if the error was successfully added, \c false if either148* Value offset exceeds the document size.149*/150bool pushError(const Value& value, const String& message, const Value& extra);151152/** \brief Return whether there are any errors.153*154* \return \c true if there are no errors to report \c false if errors have155* occurred.156*/157bool good() const;158159private:160enum TokenType {161tokenEndOfStream = 0,162tokenObjectBegin,163tokenObjectEnd,164tokenArrayBegin,165tokenArrayEnd,166tokenString,167tokenNumber,168tokenTrue,169tokenFalse,170tokenNull,171tokenArraySeparator,172tokenMemberSeparator,173tokenComment,174tokenError175};176177class Token {178public:179TokenType type_;180Location start_;181Location end_;182};183184class ErrorInfo {185public:186Token token_;187String message_;188Location extra_;189};190191using Errors = std::deque<ErrorInfo>;192193bool readToken(Token& token);194bool readTokenSkippingComments(Token& token);195void skipSpaces();196bool match(const Char* pattern, int patternLength);197bool readComment();198bool readCStyleComment();199bool readCppStyleComment();200bool readString();201void readNumber();202bool readValue();203bool readObject(Token& token);204bool readArray(Token& token);205bool decodeNumber(Token& token);206bool decodeNumber(Token& token, Value& decoded);207bool decodeString(Token& token);208bool decodeString(Token& token, String& decoded);209bool decodeDouble(Token& token);210bool decodeDouble(Token& token, Value& decoded);211bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,212unsigned int& unicode);213bool decodeUnicodeEscapeSequence(Token& token, Location& current,214Location end, unsigned int& unicode);215bool addError(const String& message, Token& token, Location extra = nullptr);216bool recoverFromError(TokenType skipUntilToken);217bool addErrorAndRecover(const String& message, Token& token,218TokenType skipUntilToken);219void skipUntilSpace();220Value& currentValue();221Char getNextChar();222void getLocationLineAndColumn(Location location, int& line,223int& column) const;224String getLocationLineAndColumn(Location location) const;225void addComment(Location begin, Location end, CommentPlacement placement);226227static bool containsNewLine(Location begin, Location end);228static String normalizeEOL(Location begin, Location end);229230using Nodes = std::stack<Value*>;231Nodes nodes_;232Errors errors_;233String document_;234Location begin_{};235Location end_{};236Location current_{};237Location lastValueEnd_{};238Value* lastValue_{};239String commentsBefore_;240Features features_;241bool collectComments_{};242}; // Reader243244/** Interface for reading JSON from a char array.245*/246class JSON_API CharReader {247public:248struct JSON_API StructuredError {249ptrdiff_t offset_start;250ptrdiff_t offset_limit;251String message;252};253254virtual ~CharReader() = default;255/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>256* document. The document must be a UTF-8 encoded string containing the257* document to read.258*259* \param beginDoc Pointer on the beginning of the UTF-8 encoded string260* of the document to read.261* \param endDoc Pointer on the end of the UTF-8 encoded string of the262* document to read. Must be >= beginDoc.263* \param[out] root Contains the root value of the document if it was264* successfully parsed.265* \param[out] errs Formatted error messages (if not NULL) a user266* friendly string that lists errors in the parsed267* document.268* \return \c true if the document was successfully parsed, \c false if an269* error occurred.270*/271virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,272String* errs);273274/** \brief Returns a vector of structured errors encountered while parsing.275* Each parse call resets the stored list of errors.276*/277std::vector<StructuredError> getStructuredErrors() const;278279class JSON_API Factory {280public:281virtual ~Factory() = default;282/** \brief Allocate a CharReader via operator new().283* \throw std::exception if something goes wrong (e.g. invalid settings)284*/285virtual CharReader* newCharReader() const = 0;286}; // Factory287288protected:289class Impl {290public:291virtual ~Impl() = default;292virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,293String* errs) = 0;294virtual std::vector<StructuredError> getStructuredErrors() const = 0;295};296297explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}298299private:300std::unique_ptr<Impl> _impl;301}; // CharReader302303/** \brief Build a CharReader implementation.304*305* Usage:306* \code307* using namespace Json;308* CharReaderBuilder builder;309* builder["collectComments"] = false;310* Value value;311* String errs;312* bool ok = parseFromStream(builder, std::cin, &value, &errs);313* \endcode314*/315class JSON_API CharReaderBuilder : public CharReader::Factory {316public:317// Note: We use a Json::Value so that we can add data-members to this class318// without a major version bump.319/** Configuration of this builder.320* These are case-sensitive.321* Available settings (case-sensitive):322* - `"collectComments": false or true`323* - true to collect comment and allow writing them back during324* serialization, false to discard comments. This parameter is ignored325* if allowComments is false.326* - `"allowComments": false or true`327* - true if comments are allowed.328* - `"allowTrailingCommas": false or true`329* - true if trailing commas in objects and arrays are allowed.330* - `"strictRoot": false or true`331* - true if root must be either an array or an object value332* - `"allowDroppedNullPlaceholders": false or true`333* - true if dropped null placeholders are allowed. (See334* StreamWriterBuilder.)335* - `"allowNumericKeys": false or true`336* - true if numeric object keys are allowed.337* - `"allowSingleQuotes": false or true`338* - true if '' are allowed for strings (both keys and values)339* - `"stackLimit": integer`340* - Exceeding stackLimit (recursive depth of `readValue()`) will cause an341* exception.342* - This is a security issue (seg-faults caused by deeply nested JSON), so343* the default is low.344* - `"failIfExtra": false or true`345* - If true, `parse()` returns false when extra non-whitespace trails the346* JSON value in the input string.347* - `"rejectDupKeys": false or true`348* - If true, `parse()` returns false when a key is duplicated within an349* object.350* - `"allowSpecialFloats": false or true`351* - If true, special float values (NaNs and infinities) are allowed and352* their values are lossfree restorable.353* - `"skipBom": false or true`354* - If true, if the input starts with the Unicode byte order mark (BOM),355* it is skipped.356*357* You can examine 'settings_` yourself to see the defaults. You can also358* write and read them just like any JSON Value.359* \sa setDefaults()360*/361Json::Value settings_;362363CharReaderBuilder();364~CharReaderBuilder() override;365366CharReader* newCharReader() const override;367368/** \return true if 'settings' are legal and consistent;369* otherwise, indicate bad settings via 'invalid'.370*/371bool validate(Json::Value* invalid) const;372373/** A simple way to update a specific setting.374*/375Value& operator[](const String& key);376377/** Called by ctor, but you can use this to reset settings_.378* \pre 'settings' != NULL (but Json::null is fine)379* \remark Defaults:380* snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults381*/382static void setDefaults(Json::Value* settings);383/** Same as old Features::strictMode().384* \pre 'settings' != NULL (but Json::null is fine)385* \remark Defaults:386* snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode387*/388static void strictMode(Json::Value* settings);389/** ECMA-404 mode.390* \pre 'settings' != NULL (but Json::null is fine)391* \remark Defaults:392* \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode393*/394static void ecma404Mode(Json::Value* settings);395};396397/** Consume entire stream and use its begin/end.398* Someday we might have a real StreamReader, but for now this399* is convenient.400*/401bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,402String* errs);403404/** \brief Read from 'sin' into 'root'.405*406* Always keep comments from the input JSON.407*408* This can be used to read a file into a particular sub-object.409* For example:410* \code411* Json::Value root;412* cin >> root["dir"]["file"];413* cout << root;414* \endcode415* Result:416* \verbatim417* {418* "dir": {419* "file": {420* // The input stream JSON would be nested here.421* }422* }423* }424* \endverbatim425* \throw std::exception on parse error.426* \see Json::operator<<()427*/428JSON_API IStream& operator>>(IStream&, Value&);429430} // namespace Json431432#if !defined(__SUNPRO_CC)433#pragma pack(pop)434#endif435436#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)437#pragma warning(pop)438#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)439440#endif // JSON_READER_H_INCLUDED441442443