mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 22:50:59 +01:00
Squashed 'src/univalue/' changes from 16a1f7f6e..fe805ea74
fe805ea74 Declare single-argument (non-converting) constructors "explicit" 8a2d6f1e3 Merge pull request #41 from jgarzik/get-obj-map ba341a20d Add getObjMap() helper method. Also, constify checkObject(). ceb119413 Handle .pushKV() and .checkObject() edge cases. 107db9829 Add ::push_back(double) method for feature parity. d41530031 Move one-line implementation of UniValue::read() to header. 52e85b35b Move exception-throwing get_* methods into separate implementation module. dac529675 README.md: update code quotes 3e31dcffb README.md: close code quote d09b8429d Update README.md f1b86edb4 Convert README to markdown style. 1dfe464ef Import UniValue class unit tests from bitcoin project. 0d3e74dd1 operator[] takes size_t index parameter (versus unsigned int) 640158fa2 Private findKey() method becomes size_t clean, and returns bool on failure. 709913585 Merge pull request #36 from ryanofsky/pr/end-str a31231b51 Version 1.0.3 4fd5444d1 Reject unterminated strings 81eba332b Merge pull request #26 from isle2983/pushBackHelpers 36405413e Merge PR #32 from branch 'nul-not-special' of git://github.com/ryanofsky/univalue into merge 89bb07322 Merge pull request #31 from ryanofsky/raw-literals 511008c36 Merge pull request #30 from ryanofsky/test-driver 77974f3a9 Merge pull request #34 from paveljanik/20161116_Wshadow_codepoint a38fcd355 Do not shadow member variable codepoint. fd32d1ab8 Don't require nul-terminated string inputs 0bb1439d0 Support parsing raw literals in UniValue 28876d045 Merge pull request #29 from btcdrak/exportspace 839ccd71f Add test driver for JSONTestSuite 26ef3fff1 Remove trailing whitespace from JSON export cfa0384d6 Convenience wrappers for push_back-ing integer types REVERT: 16a1f7f6e Merge #3: Pull upstream REVERT: daf1285af Merge pull request #2 from jgarzik/master REVERT: f32df99e9 Merge branch '2016_04_unicode' into bitcoin REVERT: 280b191cb Merge remote-tracking branch 'jgarzik/master' into bitcoin REVERT: 2740c4f71 Merge branch '2015_11_escape_plan' into bitcoin git-subtree-dir: src/univalue git-subtree-split: fe805ea74f8919382720b09a905a14e81311b3ad
This commit is contained in:
195
lib/univalue.cpp
195
lib/univalue.cpp
@@ -4,75 +4,12 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "univalue.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool ParsePrechecks(const std::string& str)
|
||||
{
|
||||
if (str.empty()) // No empty string allowed
|
||||
return false;
|
||||
if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
|
||||
return false;
|
||||
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseInt32(const std::string& str, int32_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = NULL;
|
||||
errno = 0; // strtol will not set errno if valid
|
||||
long int n = strtol(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int32_t)n;
|
||||
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
||||
// platforms the size of these types may be different.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int32_t>::min() &&
|
||||
n <= std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
|
||||
bool ParseInt64(const std::string& str, int64_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = NULL;
|
||||
errno = 0; // strtoll will not set errno if valid
|
||||
long long int n = strtoll(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int64_t)n;
|
||||
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int64_t*.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int64_t>::min() &&
|
||||
n <= std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
|
||||
bool ParseDouble(const std::string& str, double *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
||||
return false;
|
||||
std::istringstream text(str);
|
||||
text.imbue(std::locale::classic());
|
||||
double result;
|
||||
text >> result;
|
||||
if(out) *out = result;
|
||||
return text.eof() && !text.fail();
|
||||
}
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
const UniValue NullUniValue;
|
||||
@@ -104,7 +41,7 @@ static bool validNumStr(const string& s)
|
||||
{
|
||||
string tokenVal;
|
||||
unsigned int consumed;
|
||||
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str());
|
||||
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
|
||||
return (tt == JTOK_NUMBER);
|
||||
}
|
||||
|
||||
@@ -189,13 +126,22 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec)
|
||||
return true;
|
||||
}
|
||||
|
||||
void UniValue::__pushKV(const std::string& key, const UniValue& val_)
|
||||
{
|
||||
keys.push_back(key);
|
||||
values.push_back(val_);
|
||||
}
|
||||
|
||||
bool UniValue::pushKV(const std::string& key, const UniValue& val_)
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
return false;
|
||||
|
||||
keys.push_back(key);
|
||||
values.push_back(val_);
|
||||
size_t idx;
|
||||
if (findKey(key, idx))
|
||||
values[idx] = val_;
|
||||
else
|
||||
__pushKV(key, val_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -204,30 +150,43 @@ bool UniValue::pushKVs(const UniValue& obj)
|
||||
if (typ != VOBJ || obj.typ != VOBJ)
|
||||
return false;
|
||||
|
||||
for (unsigned int i = 0; i < obj.keys.size(); i++) {
|
||||
keys.push_back(obj.keys[i]);
|
||||
values.push_back(obj.values.at(i));
|
||||
}
|
||||
for (size_t i = 0; i < obj.keys.size(); i++)
|
||||
__pushKV(obj.keys[i], obj.values.at(i));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int UniValue::findKey(const std::string& key) const
|
||||
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
|
||||
{
|
||||
for (unsigned int i = 0; i < keys.size(); i++) {
|
||||
if (keys[i] == key)
|
||||
return (int) i;
|
||||
}
|
||||
if (typ != VOBJ)
|
||||
return;
|
||||
|
||||
return -1;
|
||||
kv.clear();
|
||||
for (size_t i = 0; i < keys.size(); i++)
|
||||
kv[keys[i]] = values[i];
|
||||
}
|
||||
|
||||
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
|
||||
bool UniValue::findKey(const std::string& key, size_t& retIdx) const
|
||||
{
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (keys[i] == key) {
|
||||
retIdx = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
return false;
|
||||
|
||||
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
|
||||
it != t.end(); ++it) {
|
||||
int idx = findKey(it->first);
|
||||
if (idx < 0)
|
||||
size_t idx = 0;
|
||||
if (!findKey(it->first, idx))
|
||||
return false;
|
||||
|
||||
if (values.at(idx).getType() != it->second)
|
||||
@@ -242,14 +201,14 @@ const UniValue& UniValue::operator[](const std::string& key) const
|
||||
if (typ != VOBJ)
|
||||
return NullUniValue;
|
||||
|
||||
int index = findKey(key);
|
||||
if (index < 0)
|
||||
size_t index = 0;
|
||||
if (!findKey(key, index))
|
||||
return NullUniValue;
|
||||
|
||||
return values.at(index);
|
||||
}
|
||||
|
||||
const UniValue& UniValue::operator[](unsigned int index) const
|
||||
const UniValue& UniValue::operator[](size_t index) const
|
||||
{
|
||||
if (typ != VOBJ && typ != VARR)
|
||||
return NullUniValue;
|
||||
@@ -283,75 +242,3 @@ const UniValue& find_value(const UniValue& obj, const std::string& name)
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& UniValue::getKeys() const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
throw std::runtime_error("JSON value is not an object as expected");
|
||||
return keys;
|
||||
}
|
||||
|
||||
const std::vector<UniValue>& UniValue::getValues() const
|
||||
{
|
||||
if (typ != VOBJ && typ != VARR)
|
||||
throw std::runtime_error("JSON value is not an object or array as expected");
|
||||
return values;
|
||||
}
|
||||
|
||||
bool UniValue::get_bool() const
|
||||
{
|
||||
if (typ != VBOOL)
|
||||
throw std::runtime_error("JSON value is not a boolean as expected");
|
||||
return getBool();
|
||||
}
|
||||
|
||||
const std::string& UniValue::get_str() const
|
||||
{
|
||||
if (typ != VSTR)
|
||||
throw std::runtime_error("JSON value is not a string as expected");
|
||||
return getValStr();
|
||||
}
|
||||
|
||||
int UniValue::get_int() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not an integer as expected");
|
||||
int32_t retval;
|
||||
if (!ParseInt32(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON integer out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t UniValue::get_int64() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not an integer as expected");
|
||||
int64_t retval;
|
||||
if (!ParseInt64(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON integer out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
double UniValue::get_real() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not a number as expected");
|
||||
double retval;
|
||||
if (!ParseDouble(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON double out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
const UniValue& UniValue::get_obj() const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
throw std::runtime_error("JSON value is not an object as expected");
|
||||
return *this;
|
||||
}
|
||||
|
||||
const UniValue& UniValue::get_array() const
|
||||
{
|
||||
if (typ != VARR)
|
||||
throw std::runtime_error("JSON value is not an array as expected");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user