json.cpp, json.h: Allow to use any string for object keys.
Convert to final key with new public function 'json::str2key()'. Rename related variables from 'key' to 'keystr'. git-svn-id: http://svn.code.sf.net/p/smartmontools/code/trunk@5292 4ea69e1a-61f1-4043-bf83-b5c94c648137pull/86/merge
parent
dc940da30c
commit
f3043a8edf
|
@ -1,5 +1,10 @@
|
|||
$Id$
|
||||
|
||||
2022-01-06 Christian Franke <franke@computer.org>
|
||||
|
||||
json.cpp, json.h: Allow to use any string for object keys.
|
||||
Convert to final key with new public function 'json::str2key()'.
|
||||
Rename related variables from 'key' to 'keystr'.
|
||||
|
||||
2022-01-06 Alex Samorukov <samm@os2.kiev.ua>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2017-21 Christian Franke
|
||||
* Copyright (C) 2017-22 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
@ -32,13 +32,18 @@ static void jassert_failed(int line, const char * expr)
|
|||
|
||||
#define jassert(expr) (!(expr) ? jassert_failed(__LINE__, #expr) : (void)0)
|
||||
|
||||
static void check_key(const char * key)
|
||||
std::string json::str2key(const char * str)
|
||||
{
|
||||
// Limit: object keys should be valid identifiers (lowercase only)
|
||||
char c = key[0];
|
||||
jassert('a' <= c && c <= 'z');
|
||||
for (int i = 1; (c = key[i]); i++)
|
||||
jassert(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || (c == '_'));
|
||||
std::string key = str;
|
||||
for (char & c : key) {
|
||||
if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || c == '_')
|
||||
continue;
|
||||
if ('A' <= c && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
else
|
||||
c = '_';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
json::ref::ref(json & js)
|
||||
|
@ -46,18 +51,18 @@ json::ref::ref(json & js)
|
|||
{
|
||||
}
|
||||
|
||||
json::ref::ref(json & js, const char * key)
|
||||
json::ref::ref(json & js, const char * keystr)
|
||||
: m_js(js)
|
||||
{
|
||||
check_key(key);
|
||||
m_path.push_back(node_info(key));
|
||||
jassert(keystr && *keystr);
|
||||
m_path.push_back(node_info(keystr));
|
||||
}
|
||||
|
||||
json::ref::ref(const ref & base, const char * key)
|
||||
json::ref::ref(const ref & base, const char * keystr)
|
||||
: m_js(base.m_js), m_path(base.m_path)
|
||||
{
|
||||
check_key(key);
|
||||
m_path.push_back(node_info(key));
|
||||
jassert(keystr && *keystr);
|
||||
m_path.push_back(node_info(keystr));
|
||||
}
|
||||
|
||||
json::ref::ref(const ref & base, int index)
|
||||
|
@ -206,11 +211,11 @@ void json::ref::set_unsafe_le128(const void * pvalue)
|
|||
void json::ref::operator+=(std::initializer_list<initlist_key_value_pair> ilist)
|
||||
{
|
||||
for (const initlist_key_value_pair & kv : ilist) {
|
||||
jassert(kv.key && *kv.key);
|
||||
jassert(kv.keystr && *kv.keystr);
|
||||
switch (kv.value.type) {
|
||||
default: operator[](kv.key) = kv.value; break;
|
||||
case nt_object: operator[](kv.key) += kv.object; break;
|
||||
case nt_array: operator[](kv.key) += kv.array; break;
|
||||
default: operator[](kv.keystr) = kv.value; break;
|
||||
case nt_object: operator[](kv.keystr) += kv.object; break;
|
||||
case nt_array: operator[](kv.keystr) += kv.array; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,25 +22,20 @@
|
|||
/// Create and print JSON output.
|
||||
class json
|
||||
{
|
||||
private:
|
||||
struct node_info
|
||||
{
|
||||
std::string key;
|
||||
int index = 0;
|
||||
|
||||
node_info() = default;
|
||||
explicit node_info(const char * key_) : key(key_) { }
|
||||
explicit node_info(int index_) : index(index_) { }
|
||||
};
|
||||
|
||||
typedef std::vector<node_info> node_path;
|
||||
|
||||
public:
|
||||
/// Return true if value is a safe JSON integer.
|
||||
/// Same as Number.isSafeInteger(value) in JavaScript.
|
||||
static bool is_safe_uint(unsigned long long value)
|
||||
{ return (value < (1ULL << 53)); }
|
||||
|
||||
/// Replace space and non-alphanumerics with '_', upper to lower case.
|
||||
static std::string str2key(const char * str);
|
||||
|
||||
/// Replace space and non-alphanumerics with '_', upper to lower case
|
||||
/// (std::string variant).
|
||||
static std::string str2key(const std::string & str)
|
||||
{ return str2key(str.c_str()); }
|
||||
|
||||
enum node_type {
|
||||
nt_unset, nt_object, nt_array,
|
||||
nt_bool, nt_int, nt_uint, nt_uint128, nt_string
|
||||
|
@ -74,23 +69,37 @@ public:
|
|||
};
|
||||
|
||||
struct initlist_key_value_pair {
|
||||
initlist_key_value_pair(const char * k, const initlist_value & v) : key(k), value(v) {}
|
||||
initlist_key_value_pair(const char * k, const initlist_value & v) : keystr(k), value(v) {}
|
||||
initlist_key_value_pair(const std::string & k, const initlist_value & v)
|
||||
: key(k.c_str()), value(v) {}
|
||||
: keystr(k.c_str()), value(v) {}
|
||||
initlist_key_value_pair(const char * k, const std::initializer_list<initlist_key_value_pair> & ilist)
|
||||
: key(k), value(nt_object), object(ilist) {}
|
||||
: keystr(k), value(nt_object), object(ilist) {}
|
||||
initlist_key_value_pair(const std::string & k, const std::initializer_list<initlist_key_value_pair> & ilist)
|
||||
: key(k.c_str()), value(nt_object), object(ilist) {}
|
||||
: keystr(k.c_str()), value(nt_object), object(ilist) {}
|
||||
initlist_key_value_pair(const char * k, const std::initializer_list<initlist_value> & ilist)
|
||||
: key(k), value(nt_array), array(ilist) {}
|
||||
: keystr(k), value(nt_array), array(ilist) {}
|
||||
initlist_key_value_pair(const std::string & k, const std::initializer_list<initlist_value> & ilist)
|
||||
: key(k.c_str()), value(nt_array), array(ilist) {}
|
||||
const char * key;
|
||||
: keystr(k.c_str()), value(nt_array), array(ilist) {}
|
||||
const char * keystr;
|
||||
initlist_value value;
|
||||
std::initializer_list<initlist_key_value_pair> object;
|
||||
std::initializer_list<initlist_value> array;
|
||||
};
|
||||
|
||||
private:
|
||||
struct node_info
|
||||
{
|
||||
std::string key;
|
||||
int index = 0;
|
||||
|
||||
node_info() = default;
|
||||
explicit node_info(const char * keystr) : key(str2key(keystr)) { }
|
||||
explicit node_info(int index_) : index(index_) { }
|
||||
};
|
||||
|
||||
typedef std::vector<node_info> node_path;
|
||||
|
||||
public:
|
||||
/// Reference to a JSON element.
|
||||
class ref
|
||||
{
|
||||
|
@ -98,12 +107,12 @@ public:
|
|||
~ref();
|
||||
|
||||
/// Return reference to object element.
|
||||
ref operator[](const char * key) const
|
||||
{ return ref(*this, key); }
|
||||
ref operator[](const char * keystr) const
|
||||
{ return ref(*this, keystr); }
|
||||
|
||||
/// Return reference to object element (std::string variant).
|
||||
ref operator[](const std::string & key) const
|
||||
{ return ref(*this, key.c_str()); }
|
||||
ref operator[](const std::string & keystr) const
|
||||
{ return ref(*this, keystr.c_str()); }
|
||||
|
||||
/// Return reference to array element.
|
||||
ref operator[](int index) const
|
||||
|
@ -146,8 +155,8 @@ public:
|
|||
private:
|
||||
friend class json;
|
||||
explicit ref(json & js);
|
||||
ref(json & js, const char * key);
|
||||
ref(const ref & base, const char * key);
|
||||
ref(json & js, const char * keystr);
|
||||
ref(const ref & base, const char * keystr);
|
||||
ref(const ref & base, int index);
|
||||
ref(const ref & base, const char * /*dummy*/, const char * key_suffix);
|
||||
|
||||
|
@ -159,12 +168,12 @@ public:
|
|||
};
|
||||
|
||||
/// Return reference to element of top level object.
|
||||
ref operator[](const char * key)
|
||||
{ return ref(*this, key); }
|
||||
ref operator[](const char * keystr)
|
||||
{ return ref(*this, keystr); }
|
||||
|
||||
/// Return reference to element of top level object (std::string variant).
|
||||
ref operator[](const std::string & key)
|
||||
{ return ref(*this, key.c_str()); }
|
||||
ref operator[](const std::string & keystr)
|
||||
{ return ref(*this, keystr.c_str()); }
|
||||
|
||||
/// Braced-init-list support for top level object.
|
||||
void operator+=(std::initializer_list<initlist_key_value_pair> ilist)
|
||||
|
|
Loading…
Reference in New Issue