bios: Implement BIOSConfig

Load the parsed json configs into memory.
And provid APIs to get/set on bios tables.

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: Ida1fedc923d31afc61dd2d4aec70d81bb6a90ae9
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
new file mode 100644
index 0000000..d5c39ba
--- /dev/null
+++ b/libpldmresponder/bios_config.cpp
@@ -0,0 +1,260 @@
+#include "bios_config.hpp"
+
+#include "bios_string_attribute.hpp"
+
+#include <fstream>
+#include <iostream>
+
+namespace pldm
+{
+namespace responder
+{
+namespace bios
+{
+namespace
+{
+
+constexpr auto enumJsonFile = "enum_attrs.json";
+constexpr auto stringJsonFile = "string_attrs.json";
+constexpr auto integerJsonFile = "integer_attrs.json";
+
+constexpr auto stringTableFile = "stringTable";
+constexpr auto attrTableFile = "attributeTable";
+constexpr auto attrValueTableFile = "attributeValueTable";
+
+} // namespace
+
+BIOSConfig::BIOSConfig(const char* jsonDir, const char* tableDir,
+                       DBusHandler* const dbusHandler) :
+    jsonDir(jsonDir),
+    tableDir(tableDir), dbusHandler(dbusHandler)
+{
+    constructAttributes();
+}
+
+void BIOSConfig::buildTables()
+{
+    fs::create_directory(tableDir);
+    auto stringTable = buildAndStoreStringTable();
+    if (stringTable)
+    {
+        buildAndStoreAttrTables(*stringTable);
+    }
+}
+
+std::optional<Table> BIOSConfig::getBIOSTable(pldm_bios_table_types tableType)
+{
+    fs::path tablePath;
+    switch (tableType)
+    {
+        case PLDM_BIOS_STRING_TABLE:
+            tablePath = tableDir / stringTableFile;
+            break;
+        case PLDM_BIOS_ATTR_TABLE:
+            tablePath = tableDir / attrTableFile;
+            break;
+        case PLDM_BIOS_ATTR_VAL_TABLE:
+            tablePath = tableDir / attrValueTableFile;
+            break;
+    }
+    return loadTable(tablePath);
+}
+
+void BIOSConfig::constructAttributes()
+{
+    load(jsonDir / stringJsonFile, [this](const Json& entry) {
+        constructAttribute<BIOSStringAttribute>(entry);
+    });
+}
+
+void BIOSConfig::buildAndStoreAttrTables(const Table& stringTable)
+{
+    BIOSStringTable biosStringTable(stringTable);
+
+    if (biosAttributes.empty())
+    {
+        return;
+    }
+
+    Table attrTable, attrValueTable;
+
+    for (auto& attr : biosAttributes)
+    {
+        try
+        {
+            attr->constructEntry(biosStringTable, attrTable, attrValueTable);
+        }
+        catch (const std::exception& e)
+        {
+            std::cerr << "Construct Table Entry Error, AttributeName = "
+                      << attr->name << std::endl;
+        }
+    }
+
+    table::appendPadAndChecksum(attrTable);
+    table::appendPadAndChecksum(attrValueTable);
+
+    storeTable(tableDir / attrTableFile, attrTable);
+    storeTable(tableDir / attrValueTableFile, attrValueTable);
+}
+
+std::optional<Table> BIOSConfig::buildAndStoreStringTable()
+{
+    std::set<std::string> strings;
+    auto handler = [&strings](const Json& entry) {
+        strings.emplace(entry.at("attribute_name"));
+    };
+
+    load(jsonDir / stringJsonFile, handler);
+    load(jsonDir / integerJsonFile, handler);
+    load(jsonDir / enumJsonFile, [&strings](const Json& entry) {
+        strings.emplace(entry.at("attribute_name"));
+        auto possibleValues = entry.at("possible_values");
+        for (auto& pv : possibleValues)
+        {
+            strings.emplace(pv);
+        }
+    });
+
+    if (strings.empty())
+    {
+        return std::nullopt;
+    }
+
+    Table table;
+    for (const auto& elem : strings)
+    {
+        table::string::constructEntry(table, elem);
+    }
+
+    table::appendPadAndChecksum(table);
+    storeTable(tableDir / stringTableFile, table);
+    return table;
+}
+
+void BIOSConfig::storeTable(const fs::path& path, const Table& table)
+{
+    BIOSTable biosTable(path.c_str());
+    biosTable.store(table);
+}
+
+std::optional<Table> BIOSConfig::loadTable(const fs::path& path)
+{
+    BIOSTable biosTable(path.c_str());
+    if (biosTable.isEmpty())
+    {
+        return std::nullopt;
+    }
+
+    Table table;
+    biosTable.load(table);
+    return table;
+}
+
+void BIOSConfig::load(const fs::path& filePath, ParseHandler handler)
+{
+    std::ifstream file;
+    Json jsonConf;
+    if (fs::exists(filePath))
+    {
+        try
+        {
+            file.open(filePath);
+            jsonConf = Json::parse(file);
+            auto entries = jsonConf.at("entries");
+            for (auto& entry : entries)
+            {
+                try
+                {
+                    handler(entry);
+                }
+                catch (const std::exception& e)
+                {
+                    std::cerr
+                        << "Failed to parse JSON config file(entry handler) : "
+                        << filePath.c_str() << ", " << e.what() << std::endl;
+                }
+            }
+        }
+        catch (const std::exception& e)
+        {
+            std::cerr << "Failed to parse JSON config file : "
+                      << filePath.c_str() << std::endl;
+        }
+    }
+}
+
+int BIOSConfig::setAttrValue(const void* entry, size_t size)
+{
+    auto attrValueTable = getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+    auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+    auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+    if (!attrValueTable || !attrTable || !stringTable)
+    {
+        return PLDM_BIOS_TABLE_UNAVAILABLE;
+    }
+
+    auto destTable =
+        table::attribute_value::updateTable(*attrValueTable, entry, size);
+
+    if (!destTable)
+    {
+        return PLDM_ERROR;
+    }
+    auto attrValueEntry =
+        reinterpret_cast<const pldm_bios_attr_val_table_entry*>(entry);
+
+    auto attrValHeader = table::attribute_value::decodeHeader(attrValueEntry);
+
+    auto attrEntry =
+        table::attribute::findByHandle(*attrTable, attrValHeader.attrHandle);
+    if (!attrEntry)
+    {
+        return PLDM_ERROR;
+    }
+
+    try
+    {
+        auto attrHeader = table::attribute::decodeHeader(attrEntry);
+
+        BIOSStringTable biosStringTable(*stringTable);
+        auto attrName = biosStringTable.findString(attrHeader.stringHandle);
+
+        auto iter = std::find_if(
+            biosAttributes.begin(), biosAttributes.end(),
+            [&attrName](const auto& attr) { return attr->name == attrName; });
+
+        if (iter == biosAttributes.end())
+        {
+            return PLDM_ERROR;
+        }
+        (*iter)->setAttrValueOnDbus(attrValueEntry, attrEntry, biosStringTable);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "Set attribute value error: " << e.what() << std::endl;
+        return PLDM_ERROR;
+    }
+
+    BIOSTable biosAttrValueTable((tableDir / attrValueTableFile).c_str());
+    biosAttrValueTable.store(*destTable);
+    return PLDM_SUCCESS;
+}
+
+void BIOSConfig::removeTables()
+{
+    try
+    {
+        fs::remove(tableDir / stringTableFile);
+        fs::remove(tableDir / attrTableFile);
+        fs::remove(tableDir / attrValueTableFile);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "Remove the tables error: " << e.what() << std::endl;
+    }
+}
+
+} // namespace bios
+} // namespace responder
+} // namespace pldm