Skip to content

Commit 52e85b3

Browse files
committed
Move exception-throwing get_* methods into separate implementation module.
1 parent dac5296 commit 52e85b3

File tree

3 files changed

+148
-135
lines changed

3 files changed

+148
-135
lines changed

Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pkgconfig_DATA = pc/libunivalue.pc
1212

1313
libunivalue_la_SOURCES = \
1414
lib/univalue.cpp \
15+
lib/univalue_get.cpp \
1516
lib/univalue_read.cpp \
1617
lib/univalue_write.cpp
1718

lib/univalue.cpp

-135
Original file line numberDiff line numberDiff line change
@@ -4,75 +4,12 @@
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

66
#include <stdint.h>
7-
#include <errno.h>
87
#include <iomanip>
9-
#include <limits>
108
#include <sstream>
11-
#include <stdexcept>
129
#include <stdlib.h>
13-
#include <string.h>
1410

1511
#include "univalue.h"
1612

17-
namespace
18-
{
19-
static bool ParsePrechecks(const std::string& str)
20-
{
21-
if (str.empty()) // No empty string allowed
22-
return false;
23-
if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
24-
return false;
25-
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
26-
return false;
27-
return true;
28-
}
29-
30-
bool ParseInt32(const std::string& str, int32_t *out)
31-
{
32-
if (!ParsePrechecks(str))
33-
return false;
34-
char *endp = NULL;
35-
errno = 0; // strtol will not set errno if valid
36-
long int n = strtol(str.c_str(), &endp, 10);
37-
if(out) *out = (int32_t)n;
38-
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
39-
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
40-
// platforms the size of these types may be different.
41-
return endp && *endp == 0 && !errno &&
42-
n >= std::numeric_limits<int32_t>::min() &&
43-
n <= std::numeric_limits<int32_t>::max();
44-
}
45-
46-
bool ParseInt64(const std::string& str, int64_t *out)
47-
{
48-
if (!ParsePrechecks(str))
49-
return false;
50-
char *endp = NULL;
51-
errno = 0; // strtoll will not set errno if valid
52-
long long int n = strtoll(str.c_str(), &endp, 10);
53-
if(out) *out = (int64_t)n;
54-
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
55-
// we still have to check that the returned value is within the range of an *int64_t*.
56-
return endp && *endp == 0 && !errno &&
57-
n >= std::numeric_limits<int64_t>::min() &&
58-
n <= std::numeric_limits<int64_t>::max();
59-
}
60-
61-
bool ParseDouble(const std::string& str, double *out)
62-
{
63-
if (!ParsePrechecks(str))
64-
return false;
65-
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
66-
return false;
67-
std::istringstream text(str);
68-
text.imbue(std::locale::classic());
69-
double result;
70-
text >> result;
71-
if(out) *out = result;
72-
return text.eof() && !text.fail();
73-
}
74-
}
75-
7613
using namespace std;
7714

7815
const UniValue NullUniValue;
@@ -285,75 +222,3 @@ const UniValue& find_value(const UniValue& obj, const std::string& name)
285222
return NullUniValue;
286223
}
287224

288-
const std::vector<std::string>& UniValue::getKeys() const
289-
{
290-
if (typ != VOBJ)
291-
throw std::runtime_error("JSON value is not an object as expected");
292-
return keys;
293-
}
294-
295-
const std::vector<UniValue>& UniValue::getValues() const
296-
{
297-
if (typ != VOBJ && typ != VARR)
298-
throw std::runtime_error("JSON value is not an object or array as expected");
299-
return values;
300-
}
301-
302-
bool UniValue::get_bool() const
303-
{
304-
if (typ != VBOOL)
305-
throw std::runtime_error("JSON value is not a boolean as expected");
306-
return getBool();
307-
}
308-
309-
const std::string& UniValue::get_str() const
310-
{
311-
if (typ != VSTR)
312-
throw std::runtime_error("JSON value is not a string as expected");
313-
return getValStr();
314-
}
315-
316-
int UniValue::get_int() const
317-
{
318-
if (typ != VNUM)
319-
throw std::runtime_error("JSON value is not an integer as expected");
320-
int32_t retval;
321-
if (!ParseInt32(getValStr(), &retval))
322-
throw std::runtime_error("JSON integer out of range");
323-
return retval;
324-
}
325-
326-
int64_t UniValue::get_int64() const
327-
{
328-
if (typ != VNUM)
329-
throw std::runtime_error("JSON value is not an integer as expected");
330-
int64_t retval;
331-
if (!ParseInt64(getValStr(), &retval))
332-
throw std::runtime_error("JSON integer out of range");
333-
return retval;
334-
}
335-
336-
double UniValue::get_real() const
337-
{
338-
if (typ != VNUM)
339-
throw std::runtime_error("JSON value is not a number as expected");
340-
double retval;
341-
if (!ParseDouble(getValStr(), &retval))
342-
throw std::runtime_error("JSON double out of range");
343-
return retval;
344-
}
345-
346-
const UniValue& UniValue::get_obj() const
347-
{
348-
if (typ != VOBJ)
349-
throw std::runtime_error("JSON value is not an object as expected");
350-
return *this;
351-
}
352-
353-
const UniValue& UniValue::get_array() const
354-
{
355-
if (typ != VARR)
356-
throw std::runtime_error("JSON value is not an array as expected");
357-
return *this;
358-
}
359-

lib/univalue_get.cpp

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Copyright 2014 BitPay Inc.
2+
// Copyright 2015 Bitcoin Core Developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#include <stdint.h>
7+
#include <errno.h>
8+
#include <string.h>
9+
#include <stdlib.h>
10+
#include <stdexcept>
11+
#include <vector>
12+
#include <limits>
13+
#include <string>
14+
15+
#include "univalue.h"
16+
17+
namespace
18+
{
19+
static bool ParsePrechecks(const std::string& str)
20+
{
21+
if (str.empty()) // No empty string allowed
22+
return false;
23+
if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
24+
return false;
25+
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
26+
return false;
27+
return true;
28+
}
29+
30+
bool ParseInt32(const std::string& str, int32_t *out)
31+
{
32+
if (!ParsePrechecks(str))
33+
return false;
34+
char *endp = NULL;
35+
errno = 0; // strtol will not set errno if valid
36+
long int n = strtol(str.c_str(), &endp, 10);
37+
if(out) *out = (int32_t)n;
38+
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
39+
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
40+
// platforms the size of these types may be different.
41+
return endp && *endp == 0 && !errno &&
42+
n >= std::numeric_limits<int32_t>::min() &&
43+
n <= std::numeric_limits<int32_t>::max();
44+
}
45+
46+
bool ParseInt64(const std::string& str, int64_t *out)
47+
{
48+
if (!ParsePrechecks(str))
49+
return false;
50+
char *endp = NULL;
51+
errno = 0; // strtoll will not set errno if valid
52+
long long int n = strtoll(str.c_str(), &endp, 10);
53+
if(out) *out = (int64_t)n;
54+
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
55+
// we still have to check that the returned value is within the range of an *int64_t*.
56+
return endp && *endp == 0 && !errno &&
57+
n >= std::numeric_limits<int64_t>::min() &&
58+
n <= std::numeric_limits<int64_t>::max();
59+
}
60+
61+
bool ParseDouble(const std::string& str, double *out)
62+
{
63+
if (!ParsePrechecks(str))
64+
return false;
65+
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
66+
return false;
67+
std::istringstream text(str);
68+
text.imbue(std::locale::classic());
69+
double result;
70+
text >> result;
71+
if(out) *out = result;
72+
return text.eof() && !text.fail();
73+
}
74+
}
75+
76+
const std::vector<std::string>& UniValue::getKeys() const
77+
{
78+
if (typ != VOBJ)
79+
throw std::runtime_error("JSON value is not an object as expected");
80+
return keys;
81+
}
82+
83+
const std::vector<UniValue>& UniValue::getValues() const
84+
{
85+
if (typ != VOBJ && typ != VARR)
86+
throw std::runtime_error("JSON value is not an object or array as expected");
87+
return values;
88+
}
89+
90+
bool UniValue::get_bool() const
91+
{
92+
if (typ != VBOOL)
93+
throw std::runtime_error("JSON value is not a boolean as expected");
94+
return getBool();
95+
}
96+
97+
const std::string& UniValue::get_str() const
98+
{
99+
if (typ != VSTR)
100+
throw std::runtime_error("JSON value is not a string as expected");
101+
return getValStr();
102+
}
103+
104+
int UniValue::get_int() const
105+
{
106+
if (typ != VNUM)
107+
throw std::runtime_error("JSON value is not an integer as expected");
108+
int32_t retval;
109+
if (!ParseInt32(getValStr(), &retval))
110+
throw std::runtime_error("JSON integer out of range");
111+
return retval;
112+
}
113+
114+
int64_t UniValue::get_int64() const
115+
{
116+
if (typ != VNUM)
117+
throw std::runtime_error("JSON value is not an integer as expected");
118+
int64_t retval;
119+
if (!ParseInt64(getValStr(), &retval))
120+
throw std::runtime_error("JSON integer out of range");
121+
return retval;
122+
}
123+
124+
double UniValue::get_real() const
125+
{
126+
if (typ != VNUM)
127+
throw std::runtime_error("JSON value is not a number as expected");
128+
double retval;
129+
if (!ParseDouble(getValStr(), &retval))
130+
throw std::runtime_error("JSON double out of range");
131+
return retval;
132+
}
133+
134+
const UniValue& UniValue::get_obj() const
135+
{
136+
if (typ != VOBJ)
137+
throw std::runtime_error("JSON value is not an object as expected");
138+
return *this;
139+
}
140+
141+
const UniValue& UniValue::get_array() const
142+
{
143+
if (typ != VARR)
144+
throw std::runtime_error("JSON value is not an array as expected");
145+
return *this;
146+
}
147+

0 commit comments

Comments
 (0)