IPZ VPD Parser support

This commit enables the app ibm-read-vpd to read the
IPZ format vpd. To build this app, the application
build must be configured with the "--enable-ibm-parser"
option.

The application populates the Inventory with the parsed
VPD data. The parser relies on a JSON config file
that maps the input VPD file path to the Inventory D-Bus
object that hosts the VPD data as properties.

The JSON file also supplies any additional interfaces
and properties that the D-Bus object should implement.

Argument required to run this application-
ibm-read-vpd --file vpd_file

Tested:

Also tested this on Rainier simulation model and verified that VPD
for FRUs is properly published as properties of D-Bus objects in the
Inventory.

Change-Id: Ic9305f25625adced7f64123589dd083e2679afbb
Signed-off-by: Alpana Kumari <alpankum@in.ibm.com>
diff --git a/impl.cpp b/impl.cpp
index 765b1ac..35a0e0f 100644
--- a/impl.cpp
+++ b/impl.cpp
@@ -23,6 +23,7 @@
 
 static constexpr auto MAC_ADDRESS_LEN_BYTES = 6;
 static constexpr auto LAST_KW = "PF";
+static constexpr auto POUND_KW = '#';
 static constexpr auto UUID_LEN_BYTES = 16;
 static constexpr auto UUID_TIME_LOW_END = 8;
 static constexpr auto UUID_TIME_MID_END = 13;
@@ -62,6 +63,7 @@
 using RecordType = uint16_t;
 using RecordLength = uint16_t;
 using KwSize = uint8_t;
+using PoundKwSize = uint16_t;
 using ECCOffset = uint16_t;
 using ECCLength = uint16_t;
 
@@ -193,16 +195,26 @@
     std::advance(iterator, nameOffset);
 
     std::string name(iterator, iterator + lengths::RECORD_NAME);
+#ifndef IPZ_PARSER
     if (supportedRecords.end() != supportedRecords.find(name))
     {
+#endif
         // If it's a record we're interested in, proceed to find
         // contained keywords and their values.
         std::advance(iterator, lengths::RECORD_NAME);
+
+#ifdef IPZ_PARSER
+        // Reverse back to RT Kw, in ipz vpd, to Read RT KW & value
+        std::advance(iterator, -(lengths::KW_NAME + sizeof(KwSize) +
+                                 lengths::RECORD_NAME));
+#endif
         auto kwMap = readKeywords(iterator);
         // Add entry for this record (and contained keyword:value pairs)
         // to the parsed vpd output.
         out.emplace(std::move(name), std::move(kwMap));
+#ifndef IPZ_PARSER
     }
+#endif
 }
 
 std::string Impl::readKwData(const internal::KeywordInfo& keyword,
@@ -312,13 +324,35 @@
             // We're done
             break;
         }
+        // Check if the Keyword is '#kw'
+        char kwNameStart = *iterator;
+
         // Jump past keyword name
         std::advance(iterator, lengths::KW_NAME);
-        // Note keyword data length
-        std::size_t length = *iterator;
-        // Jump past keyword length
-        std::advance(iterator, sizeof(KwSize));
+
+        std::size_t length;
+        std::size_t lengthHighByte;
+        if (POUND_KW == kwNameStart)
+        {
+            // Note keyword data length
+            length = *iterator;
+            lengthHighByte = *(iterator + 1);
+            length |= (lengthHighByte << 8);
+
+            // Jump past 2Byte keyword length
+            std::advance(iterator, sizeof(PoundKwSize));
+        }
+        else
+        {
+            // Note keyword data length
+            length = *iterator;
+
+            // Jump past keyword length
+            std::advance(iterator, sizeof(KwSize));
+        }
+
         // Pointing to keyword data now
+#ifndef IPZ_PARSER
         if (supportedKeywords.end() != supportedKeywords.find(kw))
         {
             // Keyword is of interest to us
@@ -326,6 +360,14 @@
                                           length, iterator);
             map.emplace(std::move(kw), std::move(data));
         }
+
+#else
+        // support all the Keywords
+        auto stop = std::next(iterator, length);
+        std::string kwdata(iterator, stop);
+        map.emplace(std::move(kw), std::move(kwdata));
+
+#endif
         // Jump past keyword data length
         std::advance(iterator, length);
     }