/* * Interactive disassembler (IDA). * Copyright (c) 1990-2021 Hex-Rays * ALL RIGHTS RESERVED. * */ #ifndef PARSEJSON_HPP #define PARSEJSON_HPP /*! \file parsejson.hpp \brief Tools for parsing JSON-formatted input See also lex.hpp/parse.hpp for finer-grained functions & documentation. */ #include //--------------------------------------------------------------------------- enum jtype_t { JT_UNKNOWN = 0, JT_NUM, JT_STR, JT_OBJ, JT_ARR, JT_BOOL, }; //--------------------------------------------------------------------------- struct jobj_t; struct jarr_t; #define DECLARE_JVALUE_HELPERS(decl) \ decl void ida_export jvalue_t_clear(jvalue_t *); \ decl void ida_export jvalue_t_copy(jvalue_t *, const jvalue_t &); struct jvalue_t; DECLARE_JVALUE_HELPERS(idaman) //------------------------------------------------------------------------- struct jvalue_t { jvalue_t() : _type(JT_UNKNOWN), _num(0) {} jvalue_t(const jvalue_t &o) : _type(JT_UNKNOWN) { jvalue_t_copy(this, o); } ~jvalue_t() { clear(); } void clear() { jvalue_t_clear(this); } jvalue_t &operator=(const jvalue_t &o) { jvalue_t_copy(this, o); return *this; } jtype_t type() const { return _type; } int64 num() const { QASSERT(1277, _type == JT_NUM); return _num; } const char *str() const { QASSERT(1278, _type == JT_STR); return _str->c_str(); } const qstring &qstr() const { QASSERT(1623, _type == JT_STR); return *_str; } const jobj_t &obj() const { QASSERT(1279, _type == JT_OBJ); return *_obj; } const jarr_t &arr() const { QASSERT(1280, _type == JT_ARR); return *_arr; } bool vbool() const { QASSERT(1281, _type == JT_BOOL); return _bool; } jobj_t &obj() { QASSERT(1282, _type == JT_OBJ); return *_obj; } jarr_t &arr() { QASSERT(1283, _type == JT_ARR); return *_arr; } //lint -sem(jvalue_t::set_str, custodial(1)) function takes ownership of its argument //lint -sem(jvalue_t::set_obj, custodial(1)) function takes ownership of its argument //lint -sem(jvalue_t::set_arr, custodial(1)) function takes ownership of its argument void set_num(int64 i) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_NUM; _num = i; } void set_str(qstring *s) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_STR; _str = s; } void set_obj(jobj_t *o) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_OBJ; _obj = o; } void set_arr(jarr_t *a) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_ARR; _arr = a; } void set_bool(bool b) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_BOOL; _bool = b; } jobj_t *extract_obj() { QASSERT(1624, _type == JT_OBJ); jobj_t *o = _obj; _obj = NULL; _type = JT_UNKNOWN; return o; } jarr_t *extract_arr() { QASSERT(1625, _type == JT_ARR); jarr_t *a = _arr; _arr = NULL; _type = JT_UNKNOWN; return a; } void swap(jvalue_t &r) { qswap(_type, r._type); qswap(_str, r._str); } private: DECLARE_JVALUE_HELPERS(friend) jtype_t _type; union { int64 _num; qstring *_str; jobj_t *_obj; jarr_t *_arr; bool _bool; }; }; DECLARE_TYPE_AS_MOVABLE(jvalue_t); typedef qvector jvalues_t; //--------------------------------------------------------------------------- struct kvp_t { qstring key; jvalue_t value; }; DECLARE_TYPE_AS_MOVABLE(kvp_t); //------------------------------------------------------------------------- struct jobj_t : public qvector { bool has_value(const char *k) const { return get_value(k) != NULL; } jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN) { jvalue_t *v = NULL; for ( size_t i = 0, _n = size(); i < _n; ++i ) { if ( at(i).key == k ) { if ( t == JT_UNKNOWN || at(i).value.type() == t ) v = &at(i).value; break; } } return v; } const jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN) const { return ((jobj_t *) this)->get_value(k, t); } const jvalue_t *get_value_or_fail(const char *k, jtype_t t=JT_UNKNOWN) const { const jvalue_t *v = get_value(k, t); QASSERT(1289, v != NULL); return v; } jvalue_t *get_value_or_new(const char *key) { jvalue_t *v = get_value(key); if ( v == NULL ) { kvp_t &kvp = push_back(); kvp.key = key; v = &kvp.value; } return v; } int64 get_num(const char *k) const { return get_value_or_fail(k)->num(); } bool get_bool(const char *k) const { return get_value_or_fail(k)->vbool(); } const char *get_str(const char *k) const { return get_value_or_fail(k)->str(); } const jobj_t &get_obj(const char *k) const { return get_value_or_fail(k)->obj(); } const jarr_t &get_arr(const char *k) const { return get_value_or_fail(k)->arr(); } #define DEFINE_FLAG_GETTER(Type, JType, GetExpr) \ bool get(Type *out, const char *k) const \ { \ const jvalue_t *v = get_value(k, JType); \ bool ok = v != NULL; \ if ( ok ) \ *out = GetExpr; \ return ok; \ } #define DEFINE_DFLT_GETTER(Type, JType, GetExpr) \ Type get(const char *k, Type dflt) const \ { \ const jvalue_t *v = get_value(k, JType); \ return v != NULL ? GetExpr : dflt; \ } #define DEFINE_SETTER(Type, SetExpr) \ void put(const char *key, Type value) \ { \ jvalue_t *v = get_value_or_new(key); \ SetExpr; \ } #define DEFINE_ACCESSORS(Type, ConstType, JType, GetExpr, SetExpr) \ DEFINE_FLAG_GETTER(ConstType, JType, GetExpr) \ DEFINE_DFLT_GETTER(ConstType, JType, GetExpr) \ DEFINE_SETTER(Type, SetExpr) DEFINE_ACCESSORS(int, int, JT_NUM, v->num(), v->set_num(value)); DEFINE_ACCESSORS(int64, int64, JT_NUM, v->num(), v->set_num(value)); DEFINE_ACCESSORS(bool, bool, JT_BOOL, v->vbool(), v->set_bool(value)); DEFINE_ACCESSORS(jarr_t *, const jarr_t *, JT_ARR, &v->arr(), v->set_arr(value)); // setter takes ownership DEFINE_ACCESSORS(jobj_t *, const jobj_t *, JT_OBJ, &v->obj(), v->set_obj(value)); // setter takes ownership DEFINE_ACCESSORS(const char *, const char *, JT_STR, v->str(), v->set_str(new qstring(value))); #undef DEFINE_ACCESSORS #undef DEFINE_SETTER #undef DEFINE_DFLT_GETTER #undef DEFINE_FLAG_GETTER bool get(qstring *out, const char *k) const { const jvalue_t *v = get_value(k, JT_STR); bool ok = v != NULL; if ( ok ) *out = v->qstr(); return ok; } const qstring &get(const char *k, const qstring &dflt) const { const jvalue_t *v = get_value(k, JT_STR); return v != NULL ? v->qstr() : dflt; } void put(const char *key, const qstring &value) { jvalue_t *v = get_value_or_new(key); v->set_str(new qstring(value)); } }; DECLARE_TYPE_AS_MOVABLE(jobj_t); //--------------------------------------------------------------------------- struct jarr_t { jvalues_t values; size_t count_items_with_type(jtype_t t) const { size_t cnt = 0; for ( size_t i = 0, n = values.size(); i < n; ++i ) if ( values[i].type() == t ) ++cnt; return cnt; } bool is_homogeneous(jtype_t t) const { return count_items_with_type(t) == values.size(); } }; DECLARE_TYPE_AS_MOVABLE(jarr_t); //--------------------------------------------------------------------------- // Note: If 'ungot_tokens' is not NULL, its contents will be used before fetching tokens from the lexer idaman THREAD_SAFE error_t ida_export parse_json(jvalue_t *out, lexer_t *lx, tokenstack_t *ungot_tokens = NULL); idaman THREAD_SAFE error_t ida_export parse_json_string(jvalue_t *out, const char *s); //------------------------------------------------------------------------- #define SJF_PRETTY 0x1 idaman THREAD_SAFE bool ida_export serialize_json( qstring *out, const jvalue_t &v, uint32 flags=0); inline THREAD_SAFE bool serialize_json( qstring *out, const jobj_t *o, uint32 flags=0) { jvalue_t v; v.set_obj((jobj_t *) o); bool rc = serialize_json(out, v, flags); v.extract_obj(); return rc; } #endif // PARSEJSON_HPP