Repository URL to install this package:
|
Version:
9.1~250226-4.fc43 ▾
|
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2025 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 <lex.hpp>
//---------------------------------------------------------------------------
enum jtype_t
{
JT_UNKNOWN = 0,
JT_NUM,
JT_STR,
JT_OBJ,
JT_ARR,
JT_BOOL,
JT_NULL,
JT_DBL,
};
//---------------------------------------------------------------------------
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; }
double vdouble() const { QASSERT(2928, _type == JT_DBL); return _double; }
jobj_t &obj() { QASSERT(1282, _type == JT_OBJ); return *_obj; }
jarr_t &arr() { QASSERT(1283, _type == JT_ARR); return *_arr; }
bool is_null() const { QASSERT(2929, _type == JT_NULL); return true; }
//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_double(double dbl) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_DBL; _double = dbl; }
void set_str(const char *s) { set_str(new qstring(s)); }
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; }
void set_null() { if ( _type != JT_UNKNOWN ) clear(); _type = JT_NULL; }
jobj_t *extract_obj() { QASSERT(1624, _type == JT_OBJ); jobj_t *o = _obj; _obj = nullptr; _type = JT_UNKNOWN; return o; }
jarr_t *extract_arr() { QASSERT(1625, _type == JT_ARR); jarr_t *a = _arr; _arr = nullptr; _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;
double _double;
qstring *_str;
jobj_t *_obj;
jarr_t *_arr;
bool _bool;
};
};
DECLARE_TYPE_AS_MOVABLE(jvalue_t);
typedef qvector<jvalue_t> jvalues_t;
//---------------------------------------------------------------------------
struct kvp_t
{
qstring key;
jvalue_t value;
};
DECLARE_TYPE_AS_MOVABLE(kvp_t);
//-------------------------------------------------------------------------
struct jobj_t : public qvector<kvp_t>
{
bool has_value(const char *k) const { return get_value(k) != nullptr; }
jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN)
{
jvalue_t *v = nullptr;
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 != nullptr);
return v;
}
jvalue_t *get_value_or_new(const char *key)
{
jvalue_t *v = get_value(key);
if ( v == nullptr )
{
kvp_t &kvp = push_back();
kvp.key = key;
v = &kvp.value;
}
return v;
}
bool del_value(const char *k)
{
for ( size_t i = 0, _n = size(); i < _n; ++i )
{
if ( at(i).key == k )
{
erase(begin() + i);
return true;
}
}
return false;
}
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(); }
double get_double(const char *k) const { return get_value_or_fail(k)->vdouble(); }
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 != nullptr; \
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 != nullptr ? 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(double, double, JT_DBL, v->vdouble(), v->set_double(value));
DEFINE_ACCESSORS(bool, bool, JT_BOOL, v->vbool(), v->set_bool(value));
//lint -sem(jobj_t::put(const char *, struct jarr_t *), custodial(2)) function takes ownership of its argument
DEFINE_ACCESSORS(jarr_t *, const jarr_t *, JT_ARR, &v->arr(), v->set_arr(value));
//lint -sem(jobj_t::put(const char *, struct jobj_t *), custodial(2)) function takes ownership of its argument
DEFINE_ACCESSORS(jobj_t *, const jobj_t *, JT_OBJ, &v->obj(), v->set_obj(value));
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 != nullptr;
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 != nullptr ? 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));
}
void put(const char *key, const jobj_t &value)
{
jvalue_t *v = get_value_or_new(key);
v->set_obj(new jobj_t(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 nullptr, 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 = nullptr);
idaman THREAD_SAFE error_t ida_export parse_json_string(jvalue_t *out, const char *s, qstring *errbuf = nullptr, const char *file_path = nullptr);
idaman THREAD_SAFE error_t ida_export parse_json_file(jvalue_t *out, const char *path, qstring *errbuf = nullptr);
//-------------------------------------------------------------------------
#define SJF_PRETTY 0x1
#define SJF_SORTED_KEYS 0x2
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