vpd-tool mfgClean: implement sync BIOS attributes

This commit implements --syncBiosAttributes feature in vpd-tool
--mfgClean. When --syncBiosAttributes is selected along with --mfgClean,
the VPD keywords which are used for backing up BIOS attributes are
updated with the BIOS attribute values read from BIOS Config Manager
service.

Test:
```
- Install BMC image on rainier_2s2u.
- Reboot and wait for BMC to reach Ready state.
- Using vpd-tool, check the value of all the System VPD keywords used
  for backing up BIOS attributes both on EEPROM and on D-Bus.
- Run vpd-tool --mfgClean --syncBiosAttributes/-s --yes
- Check return code
- Use pldmtool to check the current values of respective BIOS attributes
- Use vpd-tool, check the value of all the System VPD keywords used for
  backing up BIOS attributes, both on EEPROM and on D-Bus.
- The VPD values should correspond with the BIOS attribute values.
- For all other keywords for which --mfgClean applies, the value on
  EEPROM and D-Bus should be the default value from the respective
  backup_restore JSON file.
```

Change-Id: I57c5df6ac0b3c4c91533d1ef22e69efcd4c87162
Signed-off-by: Souvik Roy <souvikroyofficial10@gmail.com>
diff --git a/vpd-tool/include/tool_utils.hpp b/vpd-tool/include/tool_utils.hpp
index d4bde8a..16253ee 100644
--- a/vpd-tool/include/tool_utils.hpp
+++ b/vpd-tool/include/tool_utils.hpp
@@ -903,5 +903,98 @@
     return l_retVal;
 }
 
+/**
+ * @brief API to call "GetAttribute" method under BIOS Config Manager.
+ *
+ * The API reads the given attribute from BIOS Config Manager and returns a
+ * variant containing current value for that attribute if the value is found.
+ * API returns an empty variant of type BiosAttributeCurrentValue in case of any
+ * error.
+ *
+ * @param[in] i_attributeName - Attribute to be read.
+ *
+ * @return Tuple of PLDM attribute Type, current attribute value and pending
+ * attribute value.
+ */
+inline types::BiosAttributeCurrentValue biosGetAttributeMethodCall(
+    const std::string& i_attributeName) noexcept
+{
+    types::BiosGetAttrRetType l_attributeVal;
+
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method = l_bus.new_method_call(
+            constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+            constants::biosConfigMgrInterface, "GetAttribute");
+        l_method.append(i_attributeName);
+
+        auto l_result = l_bus.call(l_method);
+        l_result.read(std::get<0>(l_attributeVal), std::get<1>(l_attributeVal),
+                      std::get<2>(l_attributeVal));
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        // TODO : enable logging when verbose is implemented
+        std::cerr << "Failed to read BIOS Attribute: " + i_attributeName +
+                         " due to error " + std::string(l_ex.what())
+                  << std::endl;
+    }
+
+    return std::get<1>(l_attributeVal);
+}
+
+/**
+ * @brief Converts string to lower case.
+ *
+ * @param [in,out] io_string - Input string.
+ *
+ * @throw std::terminate, std::bad_alloc
+ */
+inline void toLower(std::string& io_string)
+{
+    std::transform(io_string.begin(), io_string.end(), io_string.begin(),
+                   [](const unsigned char& l_char) {
+                       return std::tolower(l_char);
+                   });
+}
+
+/**
+ * @brief Converts an integral data value to a vector of bytes.
+ * The LSB of integer is copied to MSB of the vector.
+ *
+ * @param[in] i_integralData - Input integral data.
+ * @param[in] i_numBytesCopy - Number of bytes to copy.
+ *
+ * @return - On success, returns the Binary vector representation of the
+ * integral data, empty binary vector otherwise.
+ *
+ * @throw std::length_error
+ */
+template <typename T>
+    requires std::integral<T>
+inline types::BinaryVector convertIntegralTypeToBytes(
+    const T& i_integralData, size_t i_numBytesCopy = constants::VALUE_1)
+{
+    types::BinaryVector l_result;
+    constexpr auto l_byteMask{0xFF};
+
+    l_result.resize(i_numBytesCopy, constants::VALUE_0);
+
+    // sanitize number of bytes to copy
+    if (i_numBytesCopy > sizeof(T))
+    {
+        i_numBytesCopy = sizeof(T);
+    }
+
+    // LSB of source -> MSB of result
+    for (size_t l_byte = 0; l_byte < i_numBytesCopy; ++l_byte)
+    {
+        l_result[l_result.size() - (l_byte + constants::VALUE_1)] =
+            (i_integralData >> (l_byte * constants::VALUE_8)) & l_byteMask;
+    }
+    return l_result;
+}
+
 } // namespace utils
 } // namespace vpd