1 #include "bios_string_attribute.hpp"
2 
3 #include "common/utils.hpp"
4 
5 #include <iostream>
6 #include <tuple>
7 #include <variant>
8 
9 using namespace pldm::utils;
10 
11 namespace pldm
12 {
13 namespace responder
14 {
15 namespace bios
16 {
17 
18 BIOSStringAttribute::BIOSStringAttribute(const Json& entry,
19                                          DBusHandler* const dbusHandler) :
20     BIOSAttribute(entry, dbusHandler)
21 {
22     std::string strTypeTmp = entry.at("string_type");
23     auto iter = strTypeMap.find(strTypeTmp);
24     if (iter == strTypeMap.end())
25     {
26         std::cerr << "Wrong string type, STRING_TYPE=" << strTypeTmp
27                   << " ATTRIBUTE_NAME=" << name << "\n";
28         throw std::invalid_argument("Wrong string type");
29     }
30     stringInfo.stringType = static_cast<uint8_t>(iter->second);
31 
32     stringInfo.minLength = entry.at("minimum_string_length");
33     stringInfo.maxLength = entry.at("maximum_string_length");
34     stringInfo.defLength = entry.at("default_string_length");
35     stringInfo.defString = entry.at("default_string");
36 
37     pldm_bios_table_attr_entry_string_info info = {
38         0,
39         readOnly,
40         stringInfo.stringType,
41         stringInfo.minLength,
42         stringInfo.maxLength,
43         stringInfo.defLength,
44         stringInfo.defString.data(),
45     };
46 
47     const char* errmsg;
48     auto rc = pldm_bios_table_attr_entry_string_info_check(&info, &errmsg);
49     if (rc != PLDM_SUCCESS)
50     {
51         std::cerr << "Wrong field for string attribute, ATTRIBUTE_NAME=" << name
52                   << " ERRMSG=" << errmsg
53                   << " MINIMUM_STRING_LENGTH=" << stringInfo.minLength
54                   << " MAXIMUM_STRING_LENGTH=" << stringInfo.maxLength
55                   << " DEFAULT_STRING_LENGTH=" << stringInfo.defLength
56                   << " DEFAULT_STRING=" << stringInfo.defString << "\n";
57         throw std::invalid_argument("Wrong field for string attribute");
58     }
59 }
60 
61 void BIOSStringAttribute::setAttrValueOnDbus(
62     const pldm_bios_attr_val_table_entry* attrValueEntry,
63     const pldm_bios_attr_table_entry*, const BIOSStringTable&)
64 {
65     if (readOnly || !dBusMap.has_value())
66     {
67         return;
68     }
69 
70     PropertyValue value =
71         table::attribute_value::decodeStringEntry(attrValueEntry);
72     dbusHandler->setDbusProperty(*dBusMap, value);
73 }
74 
75 std::string BIOSStringAttribute::getAttrValue()
76 {
77     if (readOnly || !dBusMap.has_value())
78     {
79         return stringInfo.defString;
80     }
81     try
82     {
83         return dbusHandler->getDbusProperty<std::string>(
84             dBusMap->objectPath.c_str(), dBusMap->propertyName.c_str(),
85             dBusMap->interface.c_str());
86     }
87     catch (const std::exception& e)
88     {
89         std::cerr << "Get String Attribute Value Error: AttributeName = "
90                   << name << std::endl;
91         return stringInfo.defString;
92     }
93 }
94 
95 void BIOSStringAttribute::constructEntry(
96     const BIOSStringTable& stringTable, Table& attrTable, Table& attrValueTable,
97     std::optional<std::variant<int64_t, std::string>> optAttributeValue)
98 {
99     pldm_bios_table_attr_entry_string_info info = {
100         stringTable.findHandle(name), readOnly,
101         stringInfo.stringType,        stringInfo.minLength,
102         stringInfo.maxLength,         stringInfo.defLength,
103         stringInfo.defString.data(),
104     };
105 
106     auto attrTableEntry =
107         table::attribute::constructStringEntry(attrTable, &info);
108     auto [attrHandle, attrType, _] =
109         table::attribute::decodeHeader(attrTableEntry);
110 
111     std::string currStr{};
112     if (optAttributeValue.has_value())
113     {
114         auto attributeValue = optAttributeValue.value();
115         if (attributeValue.index() == 1)
116         {
117             currStr = std::get<std::string>(attributeValue);
118         }
119         else
120         {
121             currStr = getAttrValue();
122         }
123     }
124     else
125     {
126         currStr = getAttrValue();
127     }
128 
129     table::attribute_value::constructStringEntry(attrValueTable, attrHandle,
130                                                  attrType, currStr);
131 }
132 
133 int BIOSStringAttribute::updateAttrVal(Table& newValue, uint16_t attrHdl,
134                                        uint8_t attrType,
135                                        const PropertyValue& newPropVal)
136 {
137     try
138     {
139         const auto& newStringValue = std::get<std::string>(newPropVal);
140         table::attribute_value::constructStringEntry(newValue, attrHdl,
141                                                      attrType, newStringValue);
142     }
143     catch (const std::bad_variant_access& e)
144     {
145         std::cerr << "invalid value passed for the property, error: "
146                   << e.what() << "\n";
147         return PLDM_ERROR;
148     }
149     return PLDM_SUCCESS;
150 }
151 
152 void BIOSStringAttribute::generateAttributeEntry(
153     const std::variant<int64_t, std::string>& attributevalue,
154     Table& attrValueEntry)
155 {
156     std::string value = std::get<std::string>(attributevalue);
157     uint16_t len = value.size();
158 
159     attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) +
160                           sizeof(uint16_t) + len - 1);
161 
162     auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
163         attrValueEntry.data());
164 
165     entry->attr_type = 1;
166     memcpy(entry->value, &len, sizeof(uint16_t));
167     memcpy(entry->value + sizeof(uint16_t), value.c_str(), value.size());
168 }
169 
170 } // namespace bios
171 } // namespace responder
172 } // namespace pldm
173