Changeset View
Changeset View
Standalone View
Standalone View
src/univalue/lib/univalue.cpp
- This file was copied to src/univalue/lib/univalue_get.cpp.
// Copyright 2014 BitPay Inc. | // Copyright 2014 BitPay Inc. | ||||
// Copyright 2015 Bitcoin Core Developers | // Copyright 2015 Bitcoin Core Developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <errno.h> | |||||
#include <iomanip> | #include <iomanip> | ||||
#include <limits> | |||||
#include <sstream> | #include <sstream> | ||||
#include <stdexcept> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | |||||
#include "univalue.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; | const UniValue NullUniValue; | ||||
void UniValue::clear() | void UniValue::clear() | ||||
{ | { | ||||
typ = VNULL; | typ = VNULL; | ||||
val.clear(); | val.clear(); | ||||
keys.clear(); | keys.clear(); | ||||
values.clear(); | values.clear(); | ||||
Show All 9 Lines | |||||
{ | { | ||||
clear(); | clear(); | ||||
typ = VBOOL; | typ = VBOOL; | ||||
if (val_) | if (val_) | ||||
val = "1"; | val = "1"; | ||||
return true; | return true; | ||||
} | } | ||||
static bool validNumStr(const string& s) | static bool validNumStr(const std::string& s) | ||||
{ | { | ||||
string tokenVal; | std::string tokenVal; | ||||
unsigned int consumed; | 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); | return (tt == JTOK_NUMBER); | ||||
} | } | ||||
bool UniValue::setNumStr(const string& val_) | bool UniValue::setNumStr(const std::string& val_) | ||||
{ | { | ||||
if (!validNumStr(val_)) | if (!validNumStr(val_)) | ||||
return false; | return false; | ||||
clear(); | clear(); | ||||
typ = VNUM; | typ = VNUM; | ||||
val = val_; | val = val_; | ||||
return true; | return true; | ||||
} | } | ||||
bool UniValue::setInt(uint64_t val_) | bool UniValue::setInt(uint64_t val_) | ||||
{ | { | ||||
ostringstream oss; | std::ostringstream oss; | ||||
oss << val_; | oss << val_; | ||||
return setNumStr(oss.str()); | return setNumStr(oss.str()); | ||||
} | } | ||||
bool UniValue::setInt(int64_t val_) | bool UniValue::setInt(int64_t val_) | ||||
{ | { | ||||
ostringstream oss; | std::ostringstream oss; | ||||
oss << val_; | oss << val_; | ||||
return setNumStr(oss.str()); | return setNumStr(oss.str()); | ||||
} | } | ||||
bool UniValue::setFloat(double val_) | bool UniValue::setFloat(double val_) | ||||
{ | { | ||||
ostringstream oss; | std::ostringstream oss; | ||||
oss << std::setprecision(16) << val_; | oss << std::setprecision(16) << val_; | ||||
bool ret = setNumStr(oss.str()); | bool ret = setNumStr(oss.str()); | ||||
typ = VNUM; | typ = VNUM; | ||||
return ret; | return ret; | ||||
} | } | ||||
bool UniValue::setStr(const string& val_) | bool UniValue::setStr(const std::string& val_) | ||||
{ | { | ||||
clear(); | clear(); | ||||
typ = VSTR; | typ = VSTR; | ||||
val = val_; | val = val_; | ||||
return true; | return true; | ||||
} | } | ||||
bool UniValue::setArray() | bool UniValue::setArray() | ||||
Show All 24 Lines | bool UniValue::push_backV(const std::vector<UniValue>& vec) | ||||
if (typ != VARR) | if (typ != VARR) | ||||
return false; | return false; | ||||
values.insert(values.end(), vec.begin(), vec.end()); | values.insert(values.end(), vec.begin(), vec.end()); | ||||
return true; | 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_) | bool UniValue::pushKV(const std::string& key, const UniValue& val_) | ||||
{ | { | ||||
if (typ != VOBJ) | if (typ != VOBJ) | ||||
return false; | return false; | ||||
keys.push_back(key); | size_t idx; | ||||
values.push_back(val_); | if (findKey(key, idx)) | ||||
values[idx] = val_; | |||||
else | |||||
__pushKV(key, val_); | |||||
return true; | return true; | ||||
} | } | ||||
bool UniValue::pushKVs(const UniValue& obj) | bool UniValue::pushKVs(const UniValue& obj) | ||||
{ | { | ||||
if (typ != VOBJ || obj.typ != VOBJ) | if (typ != VOBJ || obj.typ != VOBJ) | ||||
return false; | return false; | ||||
for (unsigned int i = 0; i < obj.keys.size(); i++) { | for (size_t i = 0; i < obj.keys.size(); i++) | ||||
keys.push_back(obj.keys[i]); | __pushKV(obj.keys[i], obj.values.at(i)); | ||||
values.push_back(obj.values.at(i)); | |||||
} | |||||
return true; | 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 (typ != VOBJ) | ||||
if (keys[i] == key) | return; | ||||
return (int) i; | |||||
kv.clear(); | |||||
for (size_t i = 0; i < keys.size(); i++) | |||||
kv[keys[i]] = values[i]; | |||||
} | } | ||||
return -1; | 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; | |||||
} | |||||
} | } | ||||
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) | 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(); | for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin(); | ||||
it != t.end(); ++it) { | it != t.end(); ++it) { | ||||
int idx = findKey(it->first); | size_t idx = 0; | ||||
if (idx < 0) | if (!findKey(it->first, idx)) | ||||
return false; | return false; | ||||
if (values.at(idx).getType() != it->second) | if (values.at(idx).getType() != it->second) | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
const UniValue& UniValue::operator[](const std::string& key) const | const UniValue& UniValue::operator[](const std::string& key) const | ||||
{ | { | ||||
if (typ != VOBJ) | if (typ != VOBJ) | ||||
return NullUniValue; | return NullUniValue; | ||||
int index = findKey(key); | size_t index = 0; | ||||
if (index < 0) | if (!findKey(key, index)) | ||||
return NullUniValue; | return NullUniValue; | ||||
return values.at(index); | 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) | if (typ != VOBJ && typ != VARR) | ||||
return NullUniValue; | return NullUniValue; | ||||
if (index >= values.size()) | if (index >= values.size()) | ||||
return NullUniValue; | return NullUniValue; | ||||
return values.at(index); | return values.at(index); | ||||
} | } | ||||
Show All 17 Lines | |||||
{ | { | ||||
for (unsigned int i = 0; i < obj.keys.size(); i++) | for (unsigned int i = 0; i < obj.keys.size(); i++) | ||||
if (obj.keys[i] == name) | if (obj.keys[i] == name) | ||||
return obj.values.at(i); | return obj.values.at(i); | ||||
return NullUniValue; | 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; | |||||
} | |||||