From eac2f9f6dd445496f83696a2e72dfeba0e8b54be Mon Sep 17 00:00:00 2001 From: Tim Aitken Date: Sat, 16 Sep 2023 09:24:27 -0700 Subject: [PATCH] implement hex-reader option --- include/json/reader.h | 2 ++ src/lib_json/json_reader.cpp | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/include/json/reader.h b/include/json/reader.h index 46975d8..9898197 100644 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -324,6 +324,8 @@ public: * - `"allowSpecialFloats": false or true` * - If true, special float values (NaNs and infinities) are allowed and * their values are lossfree restorable. + * - `"allowHexadecimal": false or true` + * - If true, allow hexadecimal (eg 0xFFFF) to be used as unsigned integers. * - `"skipBom": false or true` * - If true, if the input starts with the Unicode byte order mark (BOM), * it is skipped. diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 1ac5e81..f2bc3c2 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -875,6 +875,7 @@ public: bool failIfExtra_; bool rejectDupKeys_; bool allowSpecialFloats_; + bool allowHexadecimal_; bool skipBom_; size_t stackLimit_; }; // OurFeatures @@ -914,6 +915,7 @@ private: tokenArrayEnd, tokenString, tokenNumber, + tokenHexadecimal, tokenTrue, tokenFalse, tokenNull, @@ -952,11 +954,14 @@ private: bool readString(); bool readStringSingleQuote(); bool readNumber(bool checkInf); + bool readHexadecimal(); bool readValue(); bool readObject(Token& token); bool readArray(Token& token); bool decodeNumber(Token& token); bool decodeNumber(Token& token, Value& decoded); + bool decodeHexadecimal(Token& token); + bool decodeHexadecimal(Token& token, Value& decoded); bool decodeString(Token& token); bool decodeString(Token& token, String& decoded); bool decodeDouble(Token& token); @@ -1191,6 +1196,12 @@ bool OurReader::readToken(Token& token) { ok = readComment(); break; case '0': + if(match("x", 1)) { + token.type_ = tokenHexadecimal; + ok = features_.allowHexadecimal_; + readHexadecimal(); + break; + } case '1': case '2': case '3': @@ -1419,6 +1430,18 @@ bool OurReader::readNumber(bool checkInf) { } return true; } + +bool OurReader::readHexadecimal(void) { + Location p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')) + c = (current_ = p) < end_ ? *p++ : '\0'; + return true; +} + bool OurReader::readString() { Char c = 0; while (current_ != end_) { @@ -1639,6 +1662,44 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { return true; } +bool OurReader::decodeHexadecimal(Token& token) { + Value decoded; + if (!decodeHexadecimal(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeHexadecimal(Token& token, Value& decoded) { + Json::LargestUInt value = 0; + constexpr Json::LargestUInt top = + Json::LargestUInt(0xF) << (sizeof(top) * 8) - 4; + + Location current = token.start_; + while (current < token.end_) { + Char c = *current++; + static_assert('A' < 'a'); + static_assert('0' < 'A'); + if (c == 'x') + continue; + else if (c >= 'a') + c -= 'a' - 10; + else if (c >= 'A') + c -= 'A' - 10; + else if (c >= '0') + c -= '0'; + else return addError( + "Contains non-hexadecimal digits.", token, current); + if (value & top) return addError( + "Number is too large for unsigned integer.", token, current); + value = value << 4 | static_cast(c); + } + decoded = value; + return true; +} + bool OurReader::decodeDouble(Token& token) { Value decoded; if (!decodeDouble(token, decoded)) @@ -1908,6 +1969,7 @@ CharReader* CharReaderBuilder::newCharReader() const { features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + features.allowHexadecimal_ = settings_["allowHexacecimal"].asBool(); features.skipBom_ = settings_["skipBom"].asBool(); return new OurCharReader(collectComments, features); } @@ -1925,6 +1987,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const { "failIfExtra", "rejectDupKeys", "allowSpecialFloats", + "allowHexacecimal", "skipBom", }; for (auto si = settings_.begin(); si != settings_.end(); ++si) {