pldmtool: Implement GetBIOSTable for attr/attrValue Table

Implement GetBIOSTable for the attribute table and attribute
value table.

Implement an iterator for bios table, it may be used in
libpldmresponder, at least in unit tests. So it's placed
in the utils namespace.

Tested:

Tested on fp5280g2, with json files:
https://gist.github.com/wangzqbj/b24558331cb35d14fca3b555ef03e458

$ pldmtool bios GetBIOSTable -t 0
...
...
PLDM StringTable:
BIOSStringHandle : BIOSString
0 : CodeUpdatePolicy
1 : Concurrent
2 : Disruptive
3 : Led
4 : Model
5 : OUTLET
6 : Off
7 : On
8 : str_example3

$ pldmtool bios GetBIOSTable -t 1
...
...
PLDM AttributeTable:
AttributeHandle: 0, AttributeNameHandle: 0(CodeUpdatePolicy)
	AttributeType: BIOSEnumerationReadOnly
	NumberOfPossibleValues: 2
		PossibleValueStringHandle[0] = 1(Concurrent)
		PossibleValueStringHandle[1] = 2(Disruptive)
	NumberOfDefaultValues: 1
		DefaultValueStringHandleIndex[0] = 0, StringHandle = 1(Concurrent)
AttributeHandle: 1, AttributeNameHandle: 3(Led)
	AttributeType: BIOSEnumeration
	NumberOfPossibleValues: 2
		PossibleValueStringHandle[0] = 6(Off)
		PossibleValueStringHandle[1] = 7(On)
	NumberOfDefaultValues: 1
		DefaultValueStringHandleIndex[0] = 0, StringHandle = 6(Off)
AttributeHandle: 2, AttributeNameHandle: 5(OUTLET)
	AttributeType: BIOSInteger
	LowerBound: 0
	UpperBound: 68002
	ScalarIncrement: 1
	DefaultValue:0
AttributeHandle: 3, AttributeNameHandle: 4(Model)
	AttributeType: BIOSString
	StringType: 0x01
	MinimumStringLength: 1
	MaximumStringLength: 100
	DefaultStringLength: 8
	DefaultString: FP5280G2
AttributeHandle: 4, AttributeNameHandle: 8(str_example3)
	AttributeType: BIOSStringReadOnly
	StringType: 0x00
	MinimumStringLength: 1
	MaximumStringLength: 100
	DefaultStringLength: 2
	DefaultString: ef

$ pldmtool bios GetBIOSTable -t 2
...
...
PLDM AttributeValueTable:
AttributeHandle: 0
	AttributeType: BIOSEnumerationReadOnly
	NumberOfCurrentValues: 1
	CurrentValueStringHandleIndex[0] = 0, StringHandle = 1(Concurrent)
AttributeHandle: 1
	AttributeType: BIOSEnumeration
	NumberOfCurrentValues: 1
	CurrentValueStringHandleIndex[0] = 0, StringHandle = 6(Off)
AttributeHandle: 2
	AttributeType: BIOSInteger
	CurrentValue: 0
AttributeHandle: 3
	AttributeType: BIOSString
	CurrentStringLength: 12
	CurrentString: powersupply0
AttributeHandle: 4
	AttributeType: BIOSStringReadOnly
	CurrentStringLength: 2
	CurrentString: ef

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: Iaf79af8267fc0afc5c53704537dd7b6dfc36a6a7
diff --git a/bios_utils.hpp b/bios_utils.hpp
new file mode 100644
index 0000000..8f9f8a9
--- /dev/null
+++ b/bios_utils.hpp
@@ -0,0 +1,140 @@
+#pragma once
+
+#include <cstring>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include "libpldm/bios_table.h"
+
+namespace pldm
+{
+namespace bios
+{
+namespace utils
+{
+
+using Table = std::vector<uint8_t>;
+
+/** @class BIOSTableIter
+ *  @brief Const Iterator of a BIOS Table
+ */
+template <pldm_bios_table_types tableType>
+class BIOSTableIter
+{
+  public:
+    /** @struct EndSentinel
+     *  @brief Auxiliary struct to delimit a range
+     */
+    struct EndSentinel
+    {
+    };
+
+    /** @struct iterator
+     *  @brief iterator owns the BIOS table
+     */
+    class iterator
+    {
+      public:
+        /** @brief Get entry type by specifying \p tableType
+         */
+        using T = typename std::conditional<
+            tableType == PLDM_BIOS_STRING_TABLE, pldm_bios_string_table_entry,
+            typename std::conditional<
+                tableType == PLDM_BIOS_ATTR_TABLE, pldm_bios_attr_table_entry,
+                typename std::conditional<tableType == PLDM_BIOS_ATTR_VAL_TABLE,
+                                          pldm_bios_attr_val_table_entry,
+                                          void>::type>::type>::type;
+        static_assert(!std::is_void<T>::value);
+
+        /** @brief Constructors iterator
+         *
+         *  @param[in] data - Pointer to a table
+         *  @param[in] length - The length of the table
+         */
+        explicit iterator(const void* data, size_t length) noexcept :
+            iter(pldm_bios_table_iter_create(data, length, tableType),
+                 pldm_bios_table_iter_free)
+        {
+        }
+
+        /** @brief Get the entry pointed by the iterator
+         *
+         *  @return Poiner to the entry
+         */
+        const T* operator*() const
+        {
+            return reinterpret_cast<const T*>(
+                pldm_bios_table_iter_value(iter.get()));
+        }
+
+        /** @brief Make the iterator point to the next entry
+         *
+         *  @return The iterator itself
+         */
+        iterator& operator++()
+        {
+            pldm_bios_table_iter_next(iter.get());
+            return *this;
+        }
+
+        /** @brief Check if the iterator ends
+         *
+         *  @return True if the iterator ends
+         */
+        bool operator==(const EndSentinel&) const
+        {
+            return pldm_bios_table_iter_is_end(iter.get());
+        }
+
+        /** @brief Check if the iterator ends
+         *
+         *  @return False if the iterator ends
+         */
+        bool operator!=(const EndSentinel& endSentinel) const
+        {
+            return !operator==(endSentinel);
+        }
+
+      private:
+        std::unique_ptr<pldm_bios_table_iter,
+                        decltype(&pldm_bios_table_iter_free)>
+            iter;
+    };
+
+    /** @brief Constructors BIOSTableIterator
+     *
+     *  @param[in] data - Pointer to a table
+     *  @param[in] length - The length of the table
+     */
+    BIOSTableIter(const void* data, size_t length) noexcept :
+        tableData(data), tableSize(length)
+    {
+    }
+
+    /** @brief Get the iterator to the beginning
+     *
+     *  @return An iterator to the beginning
+     */
+    iterator begin()
+    {
+        return iterator(tableData, tableSize);
+    }
+
+    /** @brief Get the iterator to the end
+     *
+     *  @return An iterator to the end
+     */
+    EndSentinel end()
+    {
+        return {};
+    }
+
+  private:
+    const void* tableData;
+    size_t tableSize;
+};
+
+} // namespace utils
+} // namespace bios
+} // namespace pldm