2013-06-18 10:20:42 +03:00
|
|
|
#ifndef _library__json__hpp__included__
|
|
|
|
#define _library__json__hpp__included__
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#include <string>
|
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <map>
|
|
|
|
#include "utf8.hpp"
|
|
|
|
|
|
|
|
namespace JSON
|
|
|
|
{
|
2013-07-06 23:21:11 +03:00
|
|
|
class node;
|
2013-06-18 10:20:42 +03:00
|
|
|
|
|
|
|
struct number_tag
|
|
|
|
{
|
|
|
|
const static int id = 2;
|
|
|
|
node operator()(double v) const;
|
|
|
|
node operator()(uint64_t v) const;
|
|
|
|
node operator()(int64_t v) const;
|
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct string_tag
|
|
|
|
{
|
|
|
|
const static int id = 3;
|
|
|
|
node operator()(const std::string& s) const;
|
|
|
|
node operator()(const std::u32string& s) const;
|
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct boolean_tag
|
|
|
|
{
|
|
|
|
const static int id = 1;
|
2013-07-06 23:21:11 +03:00
|
|
|
node operator()(bool v);
|
2013-06-18 10:20:42 +03:00
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct array_tag
|
|
|
|
{
|
|
|
|
const static int id = 4;
|
|
|
|
node operator()() const;
|
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct object_tag {
|
|
|
|
const static int id = 5;
|
|
|
|
node operator()() const;
|
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct null_tag
|
|
|
|
{
|
|
|
|
const static int id = 0;
|
|
|
|
node operator()() const;
|
2013-07-06 23:21:11 +03:00
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
2013-06-18 10:20:42 +03:00
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
2013-10-20 21:18:27 +03:00
|
|
|
struct none_tag
|
|
|
|
{
|
|
|
|
const static int id = -1;
|
|
|
|
bool operator==(const int& n) const { return n == id; }
|
|
|
|
bool operator!=(const int& n) const { return !(*this == n); }
|
|
|
|
operator int() { return id; }
|
|
|
|
};
|
|
|
|
|
2013-06-18 10:20:42 +03:00
|
|
|
extern number_tag number;
|
|
|
|
extern string_tag string;
|
|
|
|
extern boolean_tag boolean;
|
|
|
|
extern array_tag array;
|
|
|
|
extern object_tag object;
|
|
|
|
extern null_tag null;
|
2013-10-20 21:18:27 +03:00
|
|
|
extern none_tag none;
|
2013-06-18 10:20:42 +03:00
|
|
|
|
|
|
|
node i(int64_t n);
|
|
|
|
node u(uint64_t n);
|
|
|
|
node f(double n);
|
|
|
|
node b(bool bl);
|
|
|
|
node s(const std::string& st);
|
|
|
|
node s(const std::u32string& st);
|
|
|
|
node n();
|
|
|
|
|
|
|
|
enum errorcode
|
|
|
|
{
|
|
|
|
ERR_OK = 0, //All OK.
|
|
|
|
ERR_NOT_A_NUMBER, //Not a number in operation expecting one.
|
|
|
|
ERR_NOT_A_STRING, //Not a string in operation expecting one.
|
|
|
|
ERR_NOT_A_BOOLEAN, //Not a boolean in operation expecting one.
|
|
|
|
ERR_NOT_AN_ARRAY, //Not an array in operation expecting one.
|
|
|
|
ERR_NOT_AN_OBJECT, //Not an object in operation expecting one.
|
|
|
|
ERR_NOT_ARRAY_NOR_OBJECT, //Not array nor object in operation expecting either.
|
|
|
|
ERR_INDEX_INVALID, //Non-existent index accessed.
|
|
|
|
ERR_KEY_INVALID, //Non-existent key accessed.
|
|
|
|
ERR_INSTANCE_INVALID, //Non-existent instance (of key) accessed.
|
|
|
|
ERR_POINTER_TRAILING_ESCAPE, //JSON pointer has trailing escape.
|
|
|
|
ERR_POINTER_INVALID_ESCAPE, //JSON pointer has invalid escape.
|
|
|
|
ERR_BAD_HEX, //Bad hexadecimal character.
|
|
|
|
ERR_INVALID_SURROGATE, //Invalid surrogate escape sequence.
|
|
|
|
ERR_INVALID_ESCAPE, //Invalid escape sequence.
|
|
|
|
ERR_TRUNCATED_STRING, //Truncated string.
|
|
|
|
ERR_UNKNOWN_TYPE, //Unknown value type.
|
|
|
|
ERR_GARBAGE_AFTER_END, //Garbage after end of JSON.
|
|
|
|
ERR_TRUNCATED_JSON, //JSON truncated.
|
|
|
|
ERR_UNEXPECTED_COMMA, //Unexpected ','.
|
|
|
|
ERR_UNEXPECTED_COLON, //Unexpected ':'.
|
|
|
|
ERR_UNEXPECTED_RIGHT_BRACE, //Unexpected '}'.
|
|
|
|
ERR_UNEXPECTED_RIGHT_BRACKET, //Unexpected ']'.
|
|
|
|
ERR_INVALID_NUMBER, //Bad number syntax.
|
|
|
|
ERR_EXPECTED_STRING_KEY, //Object key is not a string.
|
|
|
|
ERR_EXPECTED_COLON, //Expected ':' here.
|
|
|
|
ERR_EXPECTED_COMMA, //Expected ',' here.
|
|
|
|
ERR_UNKNOWN_CHARACTER, //Unknown token type.
|
|
|
|
ERR_POINTER_BAD_APPEND, //Bad JSON pointer append.
|
|
|
|
ERR_POINTER_BAD_INDEX, //Bad JSON pointer index.
|
|
|
|
ERR_ITERATOR_END, //Iterator already at end.
|
|
|
|
ERR_ITERATOR_DELETED, //Iterator points to deleted object.
|
|
|
|
ERR_WRONG_OBJECT, //Iterator points to wrong object.
|
|
|
|
ERR_ILLEGAL_CHARACTER, //Illegal character generated by escape.
|
|
|
|
ERR_CONTROL_CHARACTER, //Control character in string.
|
|
|
|
ERR_UNKNOWN_SUBTYPE, //Unknown value subtype.
|
|
|
|
ERR_PATCH_BAD, //Bad JSON patch.
|
|
|
|
ERR_PATCH_TEST_FAILED, //TEST operation in patch failed.
|
|
|
|
ERR_PATCH_ILLEGAL_MOVE, //MOVE operation in patch illegal.
|
|
|
|
};
|
|
|
|
|
2013-10-20 21:18:27 +03:00
|
|
|
enum parsestate
|
|
|
|
{
|
|
|
|
PARSE_NOT_PARSING = 0, //Not parsing.
|
|
|
|
PARSE_ARRAY_AFTER_VALUE, //After value in array
|
|
|
|
PARSE_END_OF_DOCUMENT, //At end of document
|
|
|
|
PARSE_OBJECT_AFTER_VALUE, //After value in object
|
|
|
|
PARSE_OBJECT_COLON, //Expecting for colon in object
|
|
|
|
PARSE_OBJECT_NAME, //Expecting name in object
|
|
|
|
PARSE_STRING_BODY, //Parsing string body
|
|
|
|
PARSE_STRING_ESCAPE, //Parsing escape in string body
|
|
|
|
PARSE_VALUE_START, //Parsing start of value
|
|
|
|
PARSE_NUMBER, //Parsing number.
|
|
|
|
};
|
|
|
|
|
2013-06-18 10:20:42 +03:00
|
|
|
extern const char* error_desc[];
|
2013-10-20 21:18:27 +03:00
|
|
|
extern const char* state_desc[];
|
2013-06-18 10:20:42 +03:00
|
|
|
|
|
|
|
struct error : public std::runtime_error
|
|
|
|
{
|
2013-10-20 21:18:27 +03:00
|
|
|
error(errorcode _code) : runtime_error(error_desc[_code]), code(_code), state(PARSE_NOT_PARSING),
|
|
|
|
position(std::string::npos) {}
|
|
|
|
error(errorcode _code, parsestate _state, size_t pos) : runtime_error(error_desc[_code]), code(_code),
|
|
|
|
state(_state), position(pos) {}
|
2013-06-18 10:20:42 +03:00
|
|
|
errorcode get_code() { return code; }
|
2013-10-20 21:18:27 +03:00
|
|
|
parsestate get_state() { return state; }
|
|
|
|
size_t get_position() { return position; }
|
|
|
|
std::pair<size_t, size_t> get_position_lc(const std::string& doc) { return get_position_lc(doc, position); }
|
|
|
|
std::pair<size_t, size_t> get_position_lc(const std::string& doc, size_t pos);
|
|
|
|
const char* what() const throw();
|
|
|
|
std::string extended_error(const std::string& doc);
|
2013-06-18 10:20:42 +03:00
|
|
|
private:
|
|
|
|
errorcode code;
|
2013-10-20 21:18:27 +03:00
|
|
|
parsestate state;
|
|
|
|
size_t position;
|
|
|
|
mutable char buffer[512];
|
|
|
|
};
|
|
|
|
|
|
|
|
class node;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A JSON pointer
|
|
|
|
*/
|
|
|
|
class pointer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
pointer();
|
|
|
|
pointer(const std::string& ptr) throw(std::bad_alloc);
|
|
|
|
pointer(const std::u32string& ptr) throw(std::bad_alloc);
|
|
|
|
pointer pastend() const throw(std::bad_alloc) { return field(U"-"); }
|
|
|
|
pointer& pastend_inplace() throw(std::bad_alloc) { return field_inplace(U"-"); }
|
|
|
|
pointer index(uint64_t idx) const throw(std::bad_alloc);
|
|
|
|
pointer& index_inplace(uint64_t idx) throw(std::bad_alloc);
|
2013-12-20 12:39:24 +02:00
|
|
|
pointer field(const std::string& fld) const throw(std::bad_alloc) { return field(utf8::to32(fld)); }
|
2013-10-20 21:18:27 +03:00
|
|
|
pointer& field_inplace(const std::string& fld) throw(std::bad_alloc)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return field_inplace(utf8::to32(fld));
|
2013-10-20 21:18:27 +03:00
|
|
|
}
|
|
|
|
pointer field(const std::u32string& fld) const throw(std::bad_alloc);
|
|
|
|
pointer& field_inplace(const std::u32string& fld) throw(std::bad_alloc);
|
|
|
|
pointer remove() const throw(std::bad_alloc);
|
|
|
|
pointer& remove_inplace() throw(std::bad_alloc);
|
2013-12-20 12:39:24 +02:00
|
|
|
std::string as_string8() const { return utf8::to8(_pointer); }
|
2013-10-20 21:18:27 +03:00
|
|
|
std::u32string as_string() const { return _pointer; }
|
|
|
|
friend std::ostream& operator<<(std::ostream& s, const pointer& p);
|
|
|
|
friend std::basic_ostream<char32_t>& operator<<(std::basic_ostream<char32_t>& s, const pointer& p);
|
|
|
|
private:
|
|
|
|
friend class node;
|
|
|
|
std::u32string _pointer;
|
2013-06-18 10:20:42 +03:00
|
|
|
};
|
|
|
|
|
2013-12-25 18:04:35 +02:00
|
|
|
/**
|
|
|
|
* A JSON pretty-printer base.
|
|
|
|
*/
|
|
|
|
class printer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~printer() throw();
|
|
|
|
/**
|
|
|
|
* Print a value that is null, boolean or integer.
|
|
|
|
*/
|
|
|
|
virtual std::string value_val(const std::string& val);
|
|
|
|
/**
|
|
|
|
* Print a string value.
|
|
|
|
*/
|
|
|
|
virtual std::string value_string(const std::u32string& s);
|
|
|
|
/**
|
|
|
|
* Print beginning of array.
|
|
|
|
*/
|
|
|
|
virtual std::string array_begin();
|
|
|
|
/**
|
|
|
|
* Print a separator in array.
|
|
|
|
*/
|
|
|
|
virtual std::string array_separator();
|
|
|
|
/**
|
|
|
|
* Print end of array.
|
|
|
|
*/
|
|
|
|
virtual std::string array_end();
|
|
|
|
/**
|
|
|
|
* Print beginning of object.
|
|
|
|
*/
|
|
|
|
virtual std::string object_begin();
|
|
|
|
/**
|
|
|
|
* Print key in object.
|
|
|
|
*/
|
|
|
|
virtual std::string object_key(const std::u32string& s);
|
|
|
|
/**
|
|
|
|
* Print field separator in object.
|
|
|
|
*/
|
|
|
|
virtual std::string object_separator();
|
|
|
|
/**
|
|
|
|
* Print end of object.
|
|
|
|
*/
|
|
|
|
virtual std::string object_end();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A JSON pretty-printer (indenting).
|
|
|
|
*/
|
|
|
|
class printer_indenting : public printer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
printer_indenting();
|
|
|
|
~printer_indenting() throw();
|
|
|
|
std::string value_val(const std::string& val);
|
|
|
|
std::string value_string(const std::u32string& s);
|
|
|
|
std::string array_begin();
|
|
|
|
std::string array_separator();
|
|
|
|
std::string array_end();
|
|
|
|
std::string object_begin();
|
|
|
|
std::string object_key(const std::u32string& s);
|
|
|
|
std::string object_separator();
|
|
|
|
std::string object_end();
|
|
|
|
private:
|
|
|
|
std::string linestart(size_t _depth);
|
|
|
|
size_t depth;
|
|
|
|
enum _state
|
|
|
|
{
|
|
|
|
S_NORMAL,
|
|
|
|
S_END,
|
|
|
|
S_COMMA,
|
|
|
|
S_START,
|
|
|
|
S_START_END,
|
|
|
|
} state;
|
|
|
|
};
|
|
|
|
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* A JSON node.
|
|
|
|
*/
|
|
|
|
class node
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Type of node.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Construct null object.
|
|
|
|
*/
|
|
|
|
node() throw();
|
|
|
|
/**
|
|
|
|
* Construct object of specified type.
|
|
|
|
*/
|
|
|
|
node(null_tag) throw();
|
|
|
|
node(boolean_tag, bool b) throw();
|
|
|
|
node(string_tag, const std::u32string& str) throw(std::bad_alloc);
|
|
|
|
node(string_tag, const std::string& str) throw(std::bad_alloc);
|
|
|
|
node(number_tag, double n) throw();
|
|
|
|
node(number_tag, int64_t n) throw();
|
|
|
|
node(number_tag, uint64_t n) throw();
|
|
|
|
node(array_tag) throw();
|
|
|
|
node(object_tag) throw();
|
|
|
|
/**
|
|
|
|
* Compare nodes.
|
|
|
|
*/
|
2013-07-06 23:21:11 +03:00
|
|
|
bool operator==(const node& n) const;
|
|
|
|
bool operator!=(const node& n) const { return !(*this == n); }
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Copy Constructor.
|
|
|
|
*/
|
|
|
|
node(const node& _node) throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Construct object from description.
|
|
|
|
*/
|
|
|
|
node(const std::string& doc) throw(std::bad_alloc, error);
|
|
|
|
/**
|
|
|
|
* Serialize document.
|
|
|
|
*/
|
2013-12-25 18:04:35 +02:00
|
|
|
std::string serialize(printer* printer = NULL) const throw(std::bad_alloc, error);
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Get type of node.
|
|
|
|
*/
|
|
|
|
int type() const throw();
|
2013-10-20 21:18:27 +03:00
|
|
|
/**
|
|
|
|
* Get type of node by pointer.
|
|
|
|
*/
|
|
|
|
int type_of(const std::u32string& pointer) const throw(std::bad_alloc);
|
|
|
|
int type_of(const std::string& pointer) const throw(std::bad_alloc)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return type_of(utf8::to32(pointer));
|
2013-10-20 21:18:27 +03:00
|
|
|
}
|
|
|
|
int type_of(const pointer& ptr) const throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
return type_of(ptr._pointer);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get type of node by pointer (indirect).
|
|
|
|
*/
|
|
|
|
int type_of_indirect(const std::u32string& pointer) const throw(std::bad_alloc);
|
|
|
|
int type_of_indirect(const std::string& pointer) const throw(std::bad_alloc)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return type_of_indirect(utf8::to32(pointer));
|
2013-10-20 21:18:27 +03:00
|
|
|
}
|
|
|
|
int type_of_indirect(const pointer& ptr) const throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
return type_of_indirect(ptr._pointer);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Resolve an indirect pointer
|
|
|
|
*/
|
|
|
|
std::u32string resolve_indirect(const std::u32string& pointer) const throw(std::bad_alloc);
|
|
|
|
std::string resolve_indirect(const std::string& pointer) const throw(std::bad_alloc)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return utf8::to8(resolve_indirect(utf8::to32(pointer)));
|
2013-10-20 21:18:27 +03:00
|
|
|
}
|
|
|
|
pointer resolve_indirect(const pointer& ptr) const throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
return pointer(resolve_indirect(ptr._pointer));
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Get double numeric value (NT_NUMBER).
|
|
|
|
*/
|
|
|
|
double as_double() const throw(error);
|
|
|
|
/**
|
|
|
|
* Get int64_t value (NT_NUMBER).
|
|
|
|
*/
|
|
|
|
int64_t as_int() const throw(error);
|
|
|
|
/**
|
|
|
|
* Get uint64_t value (NT_NUMBER).
|
|
|
|
*/
|
|
|
|
uint64_t as_uint() const throw(error);
|
|
|
|
/**
|
|
|
|
* Read the string as UTF-8 (NT_STRING).
|
|
|
|
*/
|
|
|
|
const std::u32string& as_string() const throw(std::bad_alloc, error);
|
2013-12-20 12:39:24 +02:00
|
|
|
std::string as_string8() const throw(std::bad_alloc, error) { return utf8::to8(as_string()); }
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Get boolean value (NT_BOOLEAN).
|
|
|
|
*/
|
|
|
|
bool as_bool() const throw(error);
|
|
|
|
/**
|
|
|
|
* Read number of indices in array (NT_ARRAY).
|
|
|
|
*/
|
|
|
|
size_t index_count() const throw(error);
|
|
|
|
/**
|
|
|
|
* Read specified index from array (NT_ARRAY).
|
|
|
|
*/
|
2013-10-23 23:45:53 +03:00
|
|
|
const node& index(size_t idx) const throw(error)
|
|
|
|
{
|
|
|
|
const node* n;
|
|
|
|
auto e = index_soft(idx, n);
|
|
|
|
if(e != ERR_OK) throw error(e);
|
|
|
|
return *n;
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Read number of indices in object key (NT_OBJECT).
|
|
|
|
*/
|
|
|
|
size_t field_count(const std::u32string& key) const throw(error);
|
|
|
|
size_t field_count(const std::string& key) const throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return field_count(utf8::to32(key));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Specified field exists (NT_OBJECT)
|
|
|
|
*/
|
|
|
|
bool field_exists(const std::u32string& key) const throw(error);
|
|
|
|
bool field_exists(const std::string& key) const throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return field_exists(utf8::to32(key));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Read specified key from object (NT_OBJECT).
|
|
|
|
*/
|
2013-10-23 23:45:53 +03:00
|
|
|
const node& field(const std::u32string& key, size_t subindex = 0) const throw(error)
|
|
|
|
{
|
|
|
|
const node* n;
|
|
|
|
auto e = field_soft(key, subindex, n);
|
|
|
|
if(e != ERR_OK) throw error(e);
|
|
|
|
return *n;
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
const node& field(const std::string& key, size_t subindex = 0) const throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return field(utf8::to32(key), subindex);
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply JSON pointer (RFC 6901).
|
|
|
|
*/
|
2013-10-23 23:45:53 +03:00
|
|
|
const node& follow(const std::u32string& pointer) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
const node* n;
|
|
|
|
auto e = follow_soft(pointer, n);
|
|
|
|
if(e != ERR_OK) throw error(e);
|
|
|
|
return *n;
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
const node& follow(const std::string& pointer) const throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return follow(utf8::to32(pointer));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
2013-10-20 21:18:27 +03:00
|
|
|
const node& follow(const pointer& ptr) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(ptr._pointer);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Apply JSON pointer (RFC 6901) following strings as indirect references.
|
|
|
|
*/
|
|
|
|
const node& follow_indirect(const std::u32string& pointer) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(resolve_indirect(pointer));
|
|
|
|
}
|
|
|
|
const node& follow_indirect(const std::string& pointer) const throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return follow_indirect(utf8::to32(pointer));
|
2013-10-20 21:18:27 +03:00
|
|
|
}
|
|
|
|
const node& follow_indirect(const pointer& ptr) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow_indirect(ptr._pointer);
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Set value of node (any).
|
|
|
|
*/
|
|
|
|
node& operator=(const node& node) throw(std::bad_alloc);
|
|
|
|
/**
|
|
|
|
* Set value of node.
|
|
|
|
*/
|
|
|
|
node& set(null_tag) throw();
|
|
|
|
node& set(boolean_tag, bool number) throw();
|
|
|
|
node& set(number_tag, double number) throw();
|
|
|
|
node& set(number_tag, int64_t number) throw();
|
|
|
|
node& set(number_tag, uint64_t number) throw();
|
|
|
|
node& set(string_tag, const std::u32string& key) throw(std::bad_alloc);
|
|
|
|
node& set(string_tag tag, const std::string& key) throw(std::bad_alloc)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return set(tag, utf8::to32(key));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Read/Write specified index from array (NT_ARRAY).
|
|
|
|
*/
|
2013-10-23 23:45:53 +03:00
|
|
|
node& index(size_t idx) throw(error)
|
|
|
|
{
|
|
|
|
node* n;
|
|
|
|
auto e = index_soft(idx, n);
|
|
|
|
if(e != ERR_OK) throw error(e);
|
|
|
|
return *n;
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Append new element to array (NT_ARRAY).
|
|
|
|
*/
|
|
|
|
node& append(const node& node) throw(std::bad_alloc, error);
|
|
|
|
/**
|
|
|
|
* Read/Write specified key from object (NT_OBJECT).
|
|
|
|
*/
|
2013-10-23 23:45:53 +03:00
|
|
|
node& field(const std::u32string& key, size_t subindex = 0) throw(error)
|
|
|
|
{
|
|
|
|
node* n;
|
|
|
|
auto e = field_soft(key, subindex, n);
|
|
|
|
if(e != ERR_OK) throw error(e);
|
|
|
|
return *n;
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
node& field(const std::string& key, size_t subindex = 0) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return field(utf8::to32(key), subindex);
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Insert new element to object (NT_OBJECT).
|
|
|
|
*/
|
|
|
|
node& insert(const std::u32string& key, const node& node) throw(std::bad_alloc, error);
|
|
|
|
node& insert(const std::string& key, const node& node) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return insert(utf8::to32(key), node);
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Apply JSON pointer (RFC 6901).
|
|
|
|
*/
|
2013-10-23 23:45:53 +03:00
|
|
|
node& follow(const std::u32string& pointer) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
node* n;
|
|
|
|
auto e = follow_soft(pointer, n);
|
|
|
|
if(e != ERR_OK) throw error(e);
|
|
|
|
return *n;
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
node& follow(const std::string& pointer) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return follow(utf8::to32(pointer));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
2013-10-20 21:18:27 +03:00
|
|
|
node& follow(const pointer& ptr) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(ptr._pointer);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Apply JSON pointer (RFC 6901) following strings as indirect references.
|
|
|
|
*/
|
|
|
|
node& follow_indirect(const std::u32string& pointer) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(resolve_indirect(pointer));
|
|
|
|
}
|
|
|
|
node& follow_indirect(const std::string& pointer) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return follow_indirect(utf8::to32(pointer));
|
2013-10-20 21:18:27 +03:00
|
|
|
}
|
|
|
|
node& follow_indirect(const pointer& ptr) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow_indirect(ptr._pointer);
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Return node specified by JSON pointer (RFC 6901). If the last component doesn't exist, it is created as NULL.
|
|
|
|
*/
|
|
|
|
node& operator[](const std::u32string& pointer) throw(std::bad_alloc, error);
|
|
|
|
node& operator[](const std::string& pointer) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return (*this)[utf8::to32(pointer)];
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
2013-10-20 21:18:27 +03:00
|
|
|
node& operator[](const pointer& ptr) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return (*this)[ptr._pointer];
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Create node at specified pointer and return it.
|
|
|
|
*/
|
|
|
|
node& insert_node(const std::u32string& pointer, const node& nwn) throw(std::bad_alloc, error);
|
|
|
|
node& insert_node(const std::string& pointer, const node& nwn) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return insert_node(utf8::to32(pointer), nwn);
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
2013-10-20 21:18:27 +03:00
|
|
|
node& insert_node(const pointer& ptr, const node& nwn) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return insert_node(ptr._pointer, nwn);
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Delete a node by pointer and return what was deleted.
|
|
|
|
*/
|
|
|
|
node delete_node(const std::u32string& pointer) throw(std::bad_alloc, error);
|
|
|
|
node delete_node(const std::string& pointer) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
return delete_node(utf8::to32(pointer));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
2013-10-20 21:18:27 +03:00
|
|
|
node delete_node(const pointer& ptr) throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return delete_node(ptr._pointer);
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Synonym for follow().
|
|
|
|
*/
|
|
|
|
const node& operator[](const std::u32string& pointer) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(pointer);
|
|
|
|
}
|
|
|
|
const node& operator[](const std::string& pointer) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(pointer);
|
|
|
|
}
|
2013-10-20 21:18:27 +03:00
|
|
|
const node& operator[](const pointer& ptr) const throw(std::bad_alloc, error)
|
|
|
|
{
|
|
|
|
return follow(ptr._pointer);
|
|
|
|
}
|
2013-06-18 10:20:42 +03:00
|
|
|
/**
|
|
|
|
* Delete an array index. The rest are shifted.
|
|
|
|
*/
|
|
|
|
void erase_index(size_t idx) throw(error);
|
|
|
|
/**
|
|
|
|
* Delete an array field. The rest are shifted.
|
|
|
|
*/
|
|
|
|
void erase_field(const std::u32string& fld, size_t idx = 0) throw(error);
|
|
|
|
void erase_field(const std::string& fld, size_t idx = 0) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
erase_field(utf8::to32(fld), idx);
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Delete an entiere array field.
|
|
|
|
*/
|
|
|
|
void erase_field_all(const std::u32string& fld) throw(error);
|
|
|
|
void erase_field_all(const std::string& fld) throw(std::bad_alloc, error)
|
|
|
|
{
|
2013-12-20 12:39:24 +02:00
|
|
|
erase_field_all(utf8::to32(fld));
|
2013-06-18 10:20:42 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Apply a JSON patch.
|
|
|
|
*/
|
|
|
|
node patch(const node& patch) const throw(std::bad_alloc, error);
|
|
|
|
/**
|
|
|
|
* Clear entiere array or object.
|
|
|
|
*/
|
|
|
|
void clear() throw(error);
|
|
|
|
/**
|
|
|
|
* Iterator.
|
|
|
|
*/
|
|
|
|
class iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
|
|
typedef node value_type;
|
|
|
|
typedef int difference_type;
|
|
|
|
typedef node& reference;
|
|
|
|
typedef node* pointer;
|
|
|
|
iterator() throw();
|
|
|
|
iterator(node& n) throw(error);
|
|
|
|
std::u32string key() throw(std::bad_alloc, error);
|
2013-12-20 12:39:24 +02:00
|
|
|
std::string key8() throw(std::bad_alloc, error) { return utf8::to8(key()); }
|
2013-06-18 10:20:42 +03:00
|
|
|
size_t index() throw(error);
|
|
|
|
node& operator*() throw(error);
|
|
|
|
node* operator->() throw(error);
|
|
|
|
iterator operator++(int) throw(error);
|
|
|
|
iterator& operator++() throw(error);
|
|
|
|
bool operator==(const iterator& i) throw();
|
|
|
|
bool operator!=(const iterator& i) throw();
|
|
|
|
private:
|
|
|
|
friend class node;
|
|
|
|
node* n;
|
|
|
|
size_t idx;
|
|
|
|
std::u32string _key;
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* Constant iterator.
|
|
|
|
*/
|
|
|
|
class const_iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
|
|
typedef node value_type;
|
|
|
|
typedef int difference_type;
|
|
|
|
typedef const node& reference;
|
|
|
|
typedef const node* pointer;
|
|
|
|
const_iterator() throw();
|
|
|
|
const_iterator(const node& n) throw(error);
|
|
|
|
std::u32string key() throw(std::bad_alloc, error);
|
2013-12-20 12:39:24 +02:00
|
|
|
std::string key8() throw(std::bad_alloc, error) { return utf8::to8(key()); }
|
2013-06-18 10:20:42 +03:00
|
|
|
size_t index() throw(error);
|
|
|
|
const node& operator*() throw(error);
|
|
|
|
const node* operator->() throw(error);
|
|
|
|
const_iterator operator++(int) throw(error);
|
|
|
|
const_iterator& operator++() throw(error);
|
|
|
|
bool operator==(const const_iterator& i) throw();
|
|
|
|
bool operator!=(const const_iterator& i) throw();
|
|
|
|
private:
|
|
|
|
const node* n;
|
|
|
|
size_t idx;
|
|
|
|
std::u32string _key;
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* Iterators
|
|
|
|
*/
|
|
|
|
const_iterator begin() const throw(error) { return const_iterator(*this); }
|
|
|
|
const_iterator end() const throw() { return const_iterator(); }
|
|
|
|
iterator begin() throw(error) { return iterator(*this); }
|
|
|
|
iterator end() throw() { return iterator(); }
|
|
|
|
/**
|
|
|
|
* Delete item pointed by iterator. The rest are shifted and new iterator is returned.
|
|
|
|
*/
|
|
|
|
iterator erase(iterator itr) throw(error);
|
|
|
|
private:
|
|
|
|
class number_holder
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
number_holder() { sub = 0; n.n0 = 0; }
|
|
|
|
number_holder(const std::string& expr, size_t& ptr, size_t len);
|
|
|
|
template<typename T> T to() const
|
|
|
|
{
|
|
|
|
switch(sub) {
|
|
|
|
case 0: return n.n0;
|
|
|
|
case 1: return n.n1;
|
|
|
|
case 2: return n.n2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
template<typename T> void from(T val);
|
|
|
|
void write(std::ostream& s) const;
|
|
|
|
bool operator==(const number_holder& h) const;
|
|
|
|
private:
|
|
|
|
template<typename T> bool cmp(const T& num) const;
|
|
|
|
unsigned sub;
|
|
|
|
union {
|
|
|
|
double n0;
|
|
|
|
uint64_t n1;
|
|
|
|
int64_t n2;
|
|
|
|
} n;
|
|
|
|
};
|
|
|
|
friend class iterator;
|
|
|
|
friend class const_iterator;
|
|
|
|
void fixup_nodes(const node& _node);
|
|
|
|
void ctor(const std::string& doc, size_t& ptr, size_t len) throw(std::bad_alloc, error);
|
|
|
|
node(const std::string& doc, size_t& ptr, size_t len) throw(std::bad_alloc, error);
|
|
|
|
template<typename T> void set_helper(T v)
|
|
|
|
{
|
|
|
|
std::u32string tmp;
|
|
|
|
vtype = number;
|
|
|
|
_number.from<T>(v);
|
|
|
|
std::swap(_string, tmp);
|
|
|
|
xarray.clear();
|
|
|
|
xobject.clear();
|
|
|
|
}
|
|
|
|
template<typename T> T get_number_helper() const
|
|
|
|
{
|
|
|
|
if(vtype != number)
|
|
|
|
throw error(ERR_NOT_A_NUMBER);
|
|
|
|
return _number.to<T>();
|
|
|
|
}
|
|
|
|
|
|
|
|
int vtype;
|
|
|
|
number_holder _number;
|
|
|
|
bool _boolean;
|
|
|
|
std::u32string _string;
|
|
|
|
std::list<node> xarray;
|
|
|
|
std::vector<node*> xarray_index;
|
|
|
|
std::map<std::u32string, std::list<node>> xobject;
|
2013-10-23 23:45:53 +03:00
|
|
|
errorcode follow_soft(const std::u32string& pointer, const node*& out) const throw(std::bad_alloc);
|
|
|
|
errorcode follow_soft(const std::u32string& pointer, node*& out) throw(std::bad_alloc);
|
|
|
|
errorcode field_soft(const std::u32string& key, size_t subindex, node*& out) throw();
|
|
|
|
errorcode field_soft(const std::u32string& key, size_t subindex, const node*& out) const throw();
|
|
|
|
errorcode index_soft(size_t index, node*& out) throw();
|
|
|
|
errorcode index_soft(size_t index, const node*& out) const throw();
|
2013-06-18 10:20:42 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const int& n, const JSON::number_tag& v);
|
|
|
|
bool operator==(const int& n, const JSON::string_tag& v);
|
|
|
|
bool operator==(const int& n, const JSON::boolean_tag& v);
|
|
|
|
bool operator==(const int& n, const JSON::array_tag& v);
|
|
|
|
bool operator==(const int& n, const JSON::object_tag& v);
|
|
|
|
bool operator==(const int& n, const JSON::null_tag& v);
|
|
|
|
bool operator!=(const int& n, const JSON::number_tag& v);
|
|
|
|
bool operator!=(const int& n, const JSON::string_tag& v);
|
|
|
|
bool operator!=(const int& n, const JSON::boolean_tag& v);
|
|
|
|
bool operator!=(const int& n, const JSON::array_tag& v);
|
|
|
|
bool operator!=(const int& n, const JSON::object_tag& v);
|
|
|
|
bool operator!=(const int& n, const JSON::null_tag& v);
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|