parser : parse keyword data section

For keywords contained in an OpenPOWER VPD record, read the keyword
data. The data may be raw or encoded in ascii. Return the
resultant data as a string.

Some keywords, such as B1 (MAC address) need to be decoded specially.

Change-Id: I64c16c60dc94e173586b20fb6a92809fbb0ac89e
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/impl.cpp b/impl.cpp
index 834cc6c..de1896f 100644
--- a/impl.cpp
+++ b/impl.cpp
@@ -1,6 +1,11 @@
+#include <sstream>
 #include <exception>
 #include <iostream>
 #include <iterator>
+#include <iomanip>
+#include <tuple>
+#include <algorithm>
+#include "defines.hpp"
 #include "impl.hpp"
 
 namespace openpower
@@ -17,6 +22,22 @@
     {"OSYS", Record::OSYS}
 };
 
+static constexpr auto MAC_ADDRESS_LEN_BYTES = 6;
+
+static const std::unordered_map<std::string,
+       internal::KeywordInfo> supportedKeywords =
+{
+    {"DR", std::make_tuple(record::Keyword::DR, keyword::Encoding::ASCII)},
+    {"PN", std::make_tuple(record::Keyword::PN, keyword::Encoding::ASCII)},
+    {"SN", std::make_tuple(record::Keyword::SN, keyword::Encoding::ASCII)},
+    {"CC", std::make_tuple(record::Keyword::CC, keyword::Encoding::ASCII)},
+    {"HW", std::make_tuple(record::Keyword::HW, keyword::Encoding::RAW)},
+    {"B1", std::make_tuple(record::Keyword::B1, keyword::Encoding::B1)},
+    {"VN", std::make_tuple(record::Keyword::VN, keyword::Encoding::ASCII)},
+    {"MB", std::make_tuple(record::Keyword::MB, keyword::Encoding::RAW)},
+    {"MM", std::make_tuple(record::Keyword::MM, keyword::Encoding::ASCII)}
+};
+
 namespace
 {
 
@@ -29,6 +50,12 @@
 using ECCOffset = uint16_t;
 using ECCLength = uint16_t;
 
+constexpr auto toHex(size_t c)
+{
+    constexpr auto map = "0123456789abcdef";
+    return map[c];
+}
+
 }
 
 namespace offsets
@@ -175,6 +202,60 @@
     }
 }
 
+std::string Impl::readKwData(const internal::KeywordInfo& keyword,
+                             std::size_t dataLength,
+                             Binary::const_iterator iterator)
+{
+    switch (std::get<keyword::Encoding>(keyword))
+    {
+        case keyword::Encoding::ASCII:
+        {
+            auto stop = std::next(iterator, dataLength);
+            return std::string(iterator, stop);
+        }
+
+        case keyword::Encoding::RAW:
+        {
+            auto stop = std::next(iterator, dataLength);
+            std::string data(iterator, stop);
+            std::string result {};
+            std::for_each(data.cbegin(), data.cend(),
+                          [&result](size_t c)
+                          {
+                              result += toHex(c >> 4);
+                              result += toHex(c & 0x0F);
+                          });
+            return result;
+        }
+
+        case keyword::Encoding::B1:
+        {
+            //B1 is MAC address, represent as AA:BB:CC:DD:EE:FF
+            auto stop = std::next(iterator, MAC_ADDRESS_LEN_BYTES);
+            std::string data(iterator, stop);
+            std::string result {};
+            auto strItr = data.cbegin();
+            size_t firstDigit = *strItr;
+            result += toHex(firstDigit >> 4);
+            result += toHex(firstDigit & 0x0F);
+            std::advance(strItr, 1);
+            std::for_each(strItr, data.cend(),
+                          [&result](size_t c)
+                          {
+                              result += ":";
+                              result += toHex(c >> 4);
+                              result += toHex(c & 0x0F);
+                          });
+            return result;
+        }
+
+        default:
+            break;
+    }
+
+    return {};
+}
+
 } // namespace parser
 } // namespace vpd
 } // namespace openpower