bios: Implement BIOSAttribute

BIOS tables are built based on json entry. When a bios attribute
is set by pldm, the corresponding dbus backend should be synchronized.

Then, the BIOSAttribute class is abstracted, and it provides the following two
interfaces

1. constructEntry: Construct the entry of the attribute/attribute-value table
2. setAttrValueOnDbus: Update the corresponding dbus backend

Specific types of attributes are implemented based on BIOSAttribute. eg
BIOSStringAttribute, BIOSEnumAttribute, BIOSIntegerAttribute.

Once the BIOS Handler is loaded, all attributes would be constructed from json.
We use BIOSConfig(class) to persist all attributes in ram.

BIOSConfig provides the following methods.

- buildTables: Build tables
- removeTables: Remove the persistent tables
- setAttrValue: Set attribute value on dbus and update the bios table
- getBIOSTable: Get bios table by table type

After we implemented BIOSConfig/BIOSSIntegerAttribute/BIOSStringAttribute/BIOSEnumAttribute,
we will use the new interface(BIOSConfig) in BIOS Handler.

It will have the following advantages

1. Different types of attribute implementations are placed in different files, improving readability
2. Logic to operate bios tables is no longer coupled with BIOS Handler.

In addition, added a c++ wrapper for string table. After
completing this refactor, will move the implementation to a common
place. It's useful for pldmtool.

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I11e304c470360ca5fde23e4969494bb03de475c0
diff --git a/libpldmresponder/bios_attribute.cpp b/libpldmresponder/bios_attribute.cpp
new file mode 100644
index 0000000..a998b53
--- /dev/null
+++ b/libpldmresponder/bios_attribute.cpp
@@ -0,0 +1,33 @@
+#include "bios_attribute.hpp"
+
+#include "utils.hpp"
+
+#include <iostream>
+#include <variant>
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+
+BIOSAttribute::BIOSAttribute(const Json& entry,
+                             DBusHandler* const dbusHandler) :
+    name(entry.at("attribute_name")),
+    readOnly(!entry.contains("dbus")), dbusHandler(dbusHandler)
+{
+    if (!readOnly)
+    {
+        std::string objectPath = entry.at("dbus").at("object_path");
+        std::string interface = entry.at("dbus").at("interface");
+        std::string propertyName = entry.at("dbus").at("property_name");
+        std::string propertyType = entry.at("dbus").at("property_type");
+
+        dBusMap = {objectPath, interface, propertyName, propertyType};
+    }
+}
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/bios_attribute.hpp b/libpldmresponder/bios_attribute.hpp
new file mode 100644
index 0000000..d63b331
--- /dev/null
+++ b/libpldmresponder/bios_attribute.hpp
@@ -0,0 +1,79 @@
+#pragma once
+
+#include "bios_table.hpp"
+#include "utils.hpp"
+
+#include <cstdint>
+#include <filesystem>
+#include <memory>
+#include <nlohmann/json.hpp>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "bios_table.h"
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+
+using Json = nlohmann::json;
+using namespace pldm::utils;
+
+/** @class BIOSAttribute
+ *  @brief Provide interfaces to implement specific types of attributes
+ */
+class BIOSAttribute
+{
+  public:
+    /** @brief Construct a bios attribute
+     *  @param[in] entry - Json Object
+     *  @param[in] dbusHandler - Dbus Handler
+     */
+    BIOSAttribute(const Json& entry, DBusHandler* const dbusHandler);
+
+    /** Virtual destructor
+     */
+    virtual ~BIOSAttribute() = default;
+
+    /** @brief Set Attribute value On Dbus according to the attribute value
+     * entry
+     *  @param[in] attrValueEntry - The attribute value entry
+     *  @param[in] attrEntry - The attribute entry corresponding to the
+     *                         attribute value entry
+     *  @param[in] stringTable - The string table
+     */
+    virtual void
+        setAttrValueOnDbus(const pldm_bios_attr_val_table_entry* attrValueEntry,
+                           const pldm_bios_attr_table_entry* attrEntry,
+                           const BIOSStringTable& stringTable) = 0;
+
+    /** @brief Construct corresponding entries at the end of the attribute table
+     *         and attribute value tables
+     *  @param[in] stringTable - The string Table
+     *  @param[in,out] attrTable - The attribute table
+     *  @param[in,out] attrValueTable - The attribute value table
+     */
+    virtual void constructEntry(const BIOSStringTable& stringTable,
+                                Table& attrTable, Table& attrValueTable) = 0;
+
+    /** @brief Name of this attribute */
+    const std::string name;
+
+    /** Weather this attribute is read-only */
+    const bool readOnly;
+
+  protected:
+    /** @brief dbus backend, nullopt if this attribute is read-only*/
+    std::optional<DBusMapping> dBusMap;
+
+    /** @brief dbus handler */
+    DBusHandler* const dbusHandler;
+};
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm
\ No newline at end of file
diff --git a/libpldmresponder/bios_table.cpp b/libpldmresponder/bios_table.cpp
index 9b7dd49..5fd6ece 100644
--- a/libpldmresponder/bios_table.cpp
+++ b/libpldmresponder/bios_table.cpp
@@ -64,13 +64,7 @@
     {
         throw std::invalid_argument("Invalid String Handle");
     }
-    auto strLength =
-        pldm_bios_table_string_entry_decode_string_length(stringEntry);
-    std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
-    pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
-                                               buffer.size());
-
-    return std::string(buffer.data(), buffer.data() + strLength);
+    return decodeString(stringEntry);
 }
 
 uint16_t BIOSStringTable::findHandle(const std::string& name) const
@@ -82,7 +76,23 @@
         throw std::invalid_argument("Invalid String Name");
     }
 
-    return pldm_bios_table_string_entry_decode_handle(stringEntry);
+    return decodeHandle(stringEntry);
+}
+
+uint16_t
+    BIOSStringTable::decodeHandle(const pldm_bios_string_table_entry* entry)
+{
+    return pldm_bios_table_string_entry_decode_handle(entry);
+}
+
+std::string
+    BIOSStringTable::decodeString(const pldm_bios_string_table_entry* entry)
+{
+    auto strLength = pldm_bios_table_string_entry_decode_string_length(entry);
+    std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
+    pldm_bios_table_string_entry_decode_string(entry, buffer.data(),
+                                               buffer.size());
+    return std::string(buffer.data(), buffer.data() + strLength);
 }
 
 } // namespace bios
diff --git a/libpldmresponder/bios_table.hpp b/libpldmresponder/bios_table.hpp
index 67503df..7b28d49 100644
--- a/libpldmresponder/bios_table.hpp
+++ b/libpldmresponder/bios_table.hpp
@@ -3,6 +3,7 @@
 #include <stdint.h>
 
 #include <filesystem>
+#include <string>
 #include <vector>
 
 #include "libpldm/bios.h"
@@ -71,7 +72,33 @@
     fs::path filePath;
 };
 
-class BIOSStringTable
+/** @class BIOSStringTableInterface
+ *  @brief Provide interfaces to the BIOS string table operations
+ */
+class BIOSStringTableInterface
+{
+  public:
+    virtual ~BIOSStringTableInterface() = default;
+
+    /** @brief Find the string name from the BIOS string table for a string
+     * handle
+     *  @param[in] handle - string handle
+     *  @return name of the corresponding BIOS string
+     */
+    virtual std::string findString(uint16_t handle) const = 0;
+
+    /** @brief Find the string handle from the BIOS string table by the given
+     *         name
+     *  @param[in] name - name of the BIOS string
+     *  @return handle of the string
+     */
+    virtual uint16_t findHandle(const std::string& name) const = 0;
+};
+
+/** @class BIOSStringTable
+ *  @brief Collection of BIOS string table operations.
+ */
+class BIOSStringTable : public BIOSStringTableInterface
 {
   public:
     /** @brief Constructs BIOSStringTable
@@ -92,7 +119,7 @@
      *  @return name of the corresponding BIOS string
      *  @throw std::invalid_argument if the string can not be found.
      */
-    std::string findString(uint16_t handle) const;
+    std::string findString(uint16_t handle) const override;
 
     /** @brief Find the string handle from the BIOS string table by the given
      *         name
@@ -100,7 +127,19 @@
      *  @return handle of the string
      *  @throw std::invalid_argument if the string can not be found
      */
-    uint16_t findHandle(const std::string& name) const;
+    uint16_t findHandle(const std::string& name) const override;
+
+    /** @brief Get the string handle for the entry
+     *  @param[in] entry - Pointer to a bios string table entry
+     *  @return Handle to identify a string in the bios string table
+     */
+    static uint16_t decodeHandle(const pldm_bios_string_table_entry* entry);
+
+    /** @brief Get the string from the entry
+     *  @param[in] entry - Pointer to a bios string table entry
+     *  @return The String
+     */
+    static std::string decodeString(const pldm_bios_string_table_entry* entry);
 
   private:
     Table stringTable;
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index cb3a7a3..2797f51 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -10,6 +10,7 @@
   'bios.cpp',
   'bios_table.cpp',
   'bios_parser.cpp',
+  'bios_attribute.cpp',
   'pdr_utils.cpp',
   'pdr.cpp',
   'platform.cpp',