Work around nlohmann changes

https://github.com/nlohmann/json/issues/4475 recently changed behavior
that we rely on in a lot of places, and unit tests appear to have caught
the failure.  Functionally, this changes the readJson* class of values
to attempt to read as the type requested first, then attempt to read as
the opposite int/uint type requested, with a range check.

In addition, the range check functions now need updated to handle
comparisons between non-similar value types.  Luckily c++20 added
cmp_less/greater type functions that we can make use of.

Tested: unit tests pass.
Change-Id: If114bd55225a3a9948e80a407b19b69f50d048b6
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp
index 60994fe..f621a45 100644
--- a/redfish-core/include/utils/json_utils.hpp
+++ b/redfish-core/include/utils/json_utils.hpp
@@ -95,8 +95,7 @@
 };
 
 template <typename ToType, typename FromType>
-bool checkRange(const FromType& from [[maybe_unused]],
-                std::string_view key [[maybe_unused]])
+bool checkRange(const FromType& from, std::string_view key)
 {
     if constexpr (std::is_floating_point_v<ToType>)
     {
@@ -105,21 +104,19 @@
             BMCWEB_LOG_DEBUG("Value for key {} was NAN", key);
             return false;
         }
+        // Assume for the moment that all floats can represent the full range
+        // of any int/uint in a cast.  This is close enough to true for the
+        // precision of this json parser.
     }
-    if constexpr (std::numeric_limits<ToType>::max() <
-                  std::numeric_limits<FromType>::max())
+    else
     {
-        if (from > std::numeric_limits<ToType>::max())
+        if (std::cmp_greater(from, std::numeric_limits<ToType>::max()))
         {
             BMCWEB_LOG_DEBUG("Value for key {} was greater than max {}", key,
                              std::numeric_limits<FromType>::max());
             return false;
         }
-    }
-    if constexpr (std::numeric_limits<ToType>::lowest() >
-                  std::numeric_limits<FromType>::lowest())
-    {
-        if (from < std::numeric_limits<ToType>::lowest())
+        if (std::cmp_less(from, std::numeric_limits<ToType>::lowest()))
         {
             BMCWEB_LOG_DEBUG("Value for key {} was less than min {}", key,
                              std::numeric_limits<FromType>::lowest());
@@ -189,13 +186,26 @@
         int64_t* jsonPtr = jsonValue.get_ptr<int64_t*>();
         if (jsonPtr == nullptr)
         {
-            return UnpackErrorCode::invalidType;
+            // Value wasn't int, check uint
+            uint64_t* uJsonPtr = jsonValue.get_ptr<uint64_t*>();
+            if (uJsonPtr == nullptr)
+            {
+                return UnpackErrorCode::invalidType;
+            }
+            if (!checkRange<Type>(*uJsonPtr, key))
+            {
+                return UnpackErrorCode::outOfRange;
+            }
+            value = static_cast<Type>(*uJsonPtr);
         }
-        if (!checkRange<Type>(*jsonPtr, key))
+        else
         {
-            return UnpackErrorCode::outOfRange;
+            if (!checkRange<Type>(*jsonPtr, key))
+            {
+                return UnpackErrorCode::outOfRange;
+            }
+            value = static_cast<Type>(*jsonPtr);
         }
-        value = static_cast<Type>(*jsonPtr);
     }
 
     else if constexpr ((std::is_unsigned_v<Type>) &&
@@ -204,13 +214,25 @@
         uint64_t* jsonPtr = jsonValue.get_ptr<uint64_t*>();
         if (jsonPtr == nullptr)
         {
-            return UnpackErrorCode::invalidType;
+            int64_t* ijsonPtr = jsonValue.get_ptr<int64_t*>();
+            if (ijsonPtr == nullptr)
+            {
+                return UnpackErrorCode::invalidType;
+            }
+            if (!checkRange<Type>(*ijsonPtr, key))
+            {
+                return UnpackErrorCode::outOfRange;
+            }
+            value = static_cast<Type>(*ijsonPtr);
         }
-        if (!checkRange<Type>(*jsonPtr, key))
+        else
         {
-            return UnpackErrorCode::outOfRange;
+            if (!checkRange<Type>(*jsonPtr, key))
+            {
+                return UnpackErrorCode::outOfRange;
+            }
+            value = static_cast<Type>(*jsonPtr);
         }
-        value = static_cast<Type>(*jsonPtr);
     }
 
     else if constexpr (std::is_same_v<nlohmann::json, Type>)
diff --git a/redfish-core/src/filter_expr_executor.cpp b/redfish-core/src/filter_expr_executor.cpp
index 838fa64..e2513e1 100644
--- a/redfish-core/src/filter_expr_executor.cpp
+++ b/redfish-core/src/filter_expr_executor.cpp
@@ -152,6 +152,17 @@
     {
         return {*iValue};
     }
+    const uint64_t* uValue = entry.get_ptr<const uint64_t*>();
+    if (uValue != nullptr)
+    {
+        // For now all values are coerced to signed
+        if (*uValue > std::numeric_limits<int64_t>::max())
+        {
+            BMCWEB_LOG_WARNING("Parsed uint is outside limits");
+            return {};
+        }
+        return {static_cast<int64_t>(*uValue)};
+    }
     const std::string* strValue = entry.get_ptr<const std::string*>();
     if (strValue != nullptr)
     {