Skip to content

Commit eac2f9f

Browse files
author
Tim Aitken
committed
implement hex-reader option
1 parent 69098a1 commit eac2f9f

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

include/json/reader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ class JSON_API CharReaderBuilder : public CharReader::Factory {
324324
* - `"allowSpecialFloats": false or true`
325325
* - If true, special float values (NaNs and infinities) are allowed and
326326
* their values are lossfree restorable.
327+
* - `"allowHexadecimal": false or true`
328+
* - If true, allow hexadecimal (eg 0xFFFF) to be used as unsigned integers.
327329
* - `"skipBom": false or true`
328330
* - If true, if the input starts with the Unicode byte order mark (BOM),
329331
* it is skipped.

src/lib_json/json_reader.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ class OurFeatures {
875875
bool failIfExtra_;
876876
bool rejectDupKeys_;
877877
bool allowSpecialFloats_;
878+
bool allowHexadecimal_;
878879
bool skipBom_;
879880
size_t stackLimit_;
880881
}; // OurFeatures
@@ -914,6 +915,7 @@ class OurReader {
914915
tokenArrayEnd,
915916
tokenString,
916917
tokenNumber,
918+
tokenHexadecimal,
917919
tokenTrue,
918920
tokenFalse,
919921
tokenNull,
@@ -952,11 +954,14 @@ class OurReader {
952954
bool readString();
953955
bool readStringSingleQuote();
954956
bool readNumber(bool checkInf);
957+
bool readHexadecimal();
955958
bool readValue();
956959
bool readObject(Token& token);
957960
bool readArray(Token& token);
958961
bool decodeNumber(Token& token);
959962
bool decodeNumber(Token& token, Value& decoded);
963+
bool decodeHexadecimal(Token& token);
964+
bool decodeHexadecimal(Token& token, Value& decoded);
960965
bool decodeString(Token& token);
961966
bool decodeString(Token& token, String& decoded);
962967
bool decodeDouble(Token& token);
@@ -1191,6 +1196,12 @@ bool OurReader::readToken(Token& token) {
11911196
ok = readComment();
11921197
break;
11931198
case '0':
1199+
if(match("x", 1)) {
1200+
token.type_ = tokenHexadecimal;
1201+
ok = features_.allowHexadecimal_;
1202+
readHexadecimal();
1203+
break;
1204+
}
11941205
case '1':
11951206
case '2':
11961207
case '3':
@@ -1419,6 +1430,18 @@ bool OurReader::readNumber(bool checkInf) {
14191430
}
14201431
return true;
14211432
}
1433+
1434+
bool OurReader::readHexadecimal(void) {
1435+
Location p = current_;
1436+
char c = '0'; // stopgap for already consumed character
1437+
// integral part
1438+
while ((c >= '0' && c <= '9')
1439+
|| (c >= 'a' && c <= 'f')
1440+
|| (c >= 'A' && c <= 'F'))
1441+
c = (current_ = p) < end_ ? *p++ : '\0';
1442+
return true;
1443+
}
1444+
14221445
bool OurReader::readString() {
14231446
Char c = 0;
14241447
while (current_ != end_) {
@@ -1639,6 +1662,44 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
16391662
return true;
16401663
}
16411664

1665+
bool OurReader::decodeHexadecimal(Token& token) {
1666+
Value decoded;
1667+
if (!decodeHexadecimal(token, decoded))
1668+
return false;
1669+
currentValue().swapPayload(decoded);
1670+
currentValue().setOffsetStart(token.start_ - begin_);
1671+
currentValue().setOffsetLimit(token.end_ - begin_);
1672+
return true;
1673+
}
1674+
1675+
bool OurReader::decodeHexadecimal(Token& token, Value& decoded) {
1676+
Json::LargestUInt value = 0;
1677+
constexpr Json::LargestUInt top =
1678+
Json::LargestUInt(0xF) << (sizeof(top) * 8) - 4;
1679+
1680+
Location current = token.start_;
1681+
while (current < token.end_) {
1682+
Char c = *current++;
1683+
static_assert('A' < 'a');
1684+
static_assert('0' < 'A');
1685+
if (c == 'x')
1686+
continue;
1687+
else if (c >= 'a')
1688+
c -= 'a' - 10;
1689+
else if (c >= 'A')
1690+
c -= 'A' - 10;
1691+
else if (c >= '0')
1692+
c -= '0';
1693+
else return addError(
1694+
"Contains non-hexadecimal digits.", token, current);
1695+
if (value & top) return addError(
1696+
"Number is too large for unsigned integer.", token, current);
1697+
value = value << 4 | static_cast<Value::UInt>(c);
1698+
}
1699+
decoded = value;
1700+
return true;
1701+
}
1702+
16421703
bool OurReader::decodeDouble(Token& token) {
16431704
Value decoded;
16441705
if (!decodeDouble(token, decoded))
@@ -1908,6 +1969,7 @@ CharReader* CharReaderBuilder::newCharReader() const {
19081969
features.failIfExtra_ = settings_["failIfExtra"].asBool();
19091970
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
19101971
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1972+
features.allowHexadecimal_ = settings_["allowHexacecimal"].asBool();
19111973
features.skipBom_ = settings_["skipBom"].asBool();
19121974
return new OurCharReader(collectComments, features);
19131975
}
@@ -1925,6 +1987,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const {
19251987
"failIfExtra",
19261988
"rejectDupKeys",
19271989
"allowSpecialFloats",
1990+
"allowHexacecimal",
19281991
"skipBom",
19291992
};
19301993
for (auto si = settings_.begin(); si != settings_.end(); ++si) {

0 commit comments

Comments
 (0)