Interface & Factory implementation for VPD Parsers

This commit abstracts the implementation logic of different parser.
A parser factory is implemented to provide instance of required
parser based on the type of vpd file needed to be parsed.

The interface should be derived to implement any further parser logic
related to vpd.

Status: This does not add any new function, so basic testing of
VPD parsing, VPD tool and writes was performed.

Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: I3ce1a2d6b7e8d8984fd7800132e78ab8a9a21e56
diff --git a/vpd-parser/keyword_vpd_parser.cpp b/vpd-parser/keyword_vpd_parser.cpp
new file mode 100644
index 0000000..3d204f4
--- /dev/null
+++ b/vpd-parser/keyword_vpd_parser.cpp
@@ -0,0 +1,221 @@
+#include "keyword_vpd_parser.hpp"
+
+#include "const.hpp"
+
+#include <iostream>
+#include <numeric>
+#include <string>
+
+using namespace openpower::vpd::constants;
+using namespace openpower::vpd::inventory;
+using namespace std;
+using namespace openpower::vpd;
+
+namespace vpd
+{
+namespace keyword
+{
+namespace parser
+{
+
+variant<KeywordVpdMap, store> KeywordVpdParser::parse()
+{
+    int kwVpdType;
+    if (keywordVpdVector.empty())
+    {
+        throw std::runtime_error("Blank Vpd Data");
+    }
+
+    validateLargeResourceIdentifierString();
+
+    kwVpdType = validateTheTypeOfKwVpd();
+
+    auto kwValMap = kwValParser();
+
+    // Donot process these two functions for bono type VPD
+    if (!kwVpdType)
+    {
+        validateSmallResourceTypeEnd();
+
+        validateChecksum();
+    }
+
+    validateSmallResourceTypeLastEnd();
+
+#ifdef DEBUG_KW_VPD
+    cerr << '\n' << " KW " << '\t' << "  VALUE " << '\n';
+    for (const auto& it : kwValMap)
+    {
+        cerr << '\n' << " " << it->first << '\t';
+        copy((it->second).begin(), (it->second).end(),
+             ostream_iterator<int>(cout << hex, " "));
+    }
+#endif
+
+    return kwValMap;
+}
+
+void KeywordVpdParser::validateLargeResourceIdentifierString()
+{
+    kwVpdIterator = keywordVpdVector.begin();
+
+    // Check for large resource type identfier string
+    if (*kwVpdIterator != KW_VPD_START_TAG)
+    {
+        throw std::runtime_error(
+            "Invalid Large resource type Identifier String");
+    }
+
+    itrOutOfBoundCheck(1);
+    advance(kwVpdIterator, sizeof(KW_VPD_START_TAG));
+}
+
+int KeywordVpdParser::validateTheTypeOfKwVpd()
+{
+    size_t dataSize = getKwDataSize();
+
+    itrOutOfBoundCheck(TWO_BYTES + dataSize);
+
+#ifdef DEBUG_KW_VPD
+    auto dsDeb = dataSize;
+    auto itDeb = kwVpdIterator + TWO_BYTES;
+    std::cout << '\n' << '\t';
+    while (dsDeb != 0)
+    {
+        std::cout << *itDeb;
+        itDeb++;
+        dsDeb--;
+    }
+    std::cout << '\n';
+#endif
+
+    // +TWO_BYTES is the description's size byte
+    std::advance(kwVpdIterator, TWO_BYTES + dataSize);
+
+    int kwVpdType = 0;
+    // Check for invalid vendor defined large resource type
+    if (*kwVpdIterator != KW_VAL_PAIR_START_TAG)
+    {
+        if (*kwVpdIterator != ALT_KW_VAL_PAIR_START_TAG)
+        {
+            throw std::runtime_error("Invalid Keyword Value Pair Start Tag");
+        }
+        // Bono vpd referred as 1
+        kwVpdType = 1;
+    }
+    return kwVpdType;
+}
+
+KeywordVpdMap KeywordVpdParser::kwValParser()
+{
+    int totalSize = 0;
+    KeywordVpdMap kwValMap;
+
+    checkSumStart = kwVpdIterator;
+
+    itrOutOfBoundCheck(1);
+    kwVpdIterator++;
+
+    // Get the total length of all keyword value pairs
+    totalSize = getKwDataSize();
+
+    if (totalSize == 0)
+    {
+        throw std::runtime_error("Badly formed keyword VPD data");
+    }
+
+    itrOutOfBoundCheck(TWO_BYTES);
+    std::advance(kwVpdIterator, TWO_BYTES);
+
+    // Parse the keyword-value and store the pairs in map
+    while (totalSize > 0)
+    {
+        std::string kwStr(kwVpdIterator, kwVpdIterator + TWO_BYTES);
+
+        totalSize -= TWO_BYTES;
+        itrOutOfBoundCheck(TWO_BYTES);
+        std::advance(kwVpdIterator, TWO_BYTES);
+
+        size_t kwSize = *kwVpdIterator;
+
+        itrOutOfBoundCheck(1);
+        kwVpdIterator++;
+
+        std::vector<uint8_t> valVec(kwVpdIterator, kwVpdIterator + kwSize);
+
+        itrOutOfBoundCheck(kwSize);
+        std::advance(kwVpdIterator, kwSize);
+
+        totalSize -= kwSize + 1;
+
+        kwValMap.emplace(std::make_pair(std::move(kwStr), std::move(valVec)));
+    }
+
+    checkSumEnd = kwVpdIterator - 1;
+
+    return kwValMap;
+}
+
+void KeywordVpdParser::validateSmallResourceTypeEnd()
+{
+    // Check for small resource type end tag
+    if (*kwVpdIterator != KW_VAL_PAIR_END_TAG)
+    {
+        throw std::runtime_error("Invalid Small resource type End");
+    }
+}
+
+void KeywordVpdParser::validateChecksum()
+{
+    uint8_t checkSum = 0;
+
+    // Checksum calculation
+    checkSum = std::accumulate(checkSumStart, checkSumEnd + 1, checkSum);
+    checkSum = ~checkSum + 1;
+
+    if (checkSum != *(kwVpdIterator + 1))
+    {
+        throw std::runtime_error("Invalid Check sum");
+    }
+#ifdef DEBUG_KW_VPD
+    std::cout << "\nCHECKSUM : " << std::hex << static_cast<int>(checkSum)
+              << std::endl;
+#endif
+
+    itrOutOfBoundCheck(TWO_BYTES);
+    std::advance(kwVpdIterator, TWO_BYTES);
+}
+
+void KeywordVpdParser::validateSmallResourceTypeLastEnd()
+{
+    // Check for small resource type last end of data
+    if (*kwVpdIterator != KW_VPD_END_TAG)
+    {
+        throw std::runtime_error(
+            "Invalid Small resource type Last End Of Data");
+    }
+}
+
+size_t KeywordVpdParser::getKwDataSize()
+{
+    return (*(kwVpdIterator + 1) << 8 | *kwVpdIterator);
+}
+
+void KeywordVpdParser::itrOutOfBoundCheck(uint8_t incVar)
+{
+
+    if ((std::distance(keywordVpdVector.begin(), kwVpdIterator + incVar)) >
+        std::distance(keywordVpdVector.begin(), keywordVpdVector.end()))
+    {
+        throw std::runtime_error("Badly formed VPD data");
+    }
+}
+
+std::string KeywordVpdParser::getInterfaceName() const
+{
+    return kwdVpdInf;
+}
+
+} // namespace parser
+} // namespace keyword
+} // namespace vpd