Correction of VPD using ECC

ECC algorithm corrects VPD data in 32:1 bit ratio in the
event of corruption.
Main Test Cases:
1) Check correction of KW in records.
2) Check correction while writing and reading VPD.
3) Check for Module VPD correction.

Signed-off-by: Giridhari Krishna <giridharikrishnan@gmail.com>
Change-Id: I48a3db18df9d3a2aecde814610ab1b357e6f310d
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index 4d81278..426dd7b 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -214,6 +214,18 @@
     return lowByte;
 }
 
+void EditorImpl::checkRecordData()
+{
+    auto itrToRecordData = vpdFile.cbegin();
+    std::advance(itrToRecordData, thisRecord.recOffset);
+
+    auto itrToRecordECC = vpdFile.cbegin();
+    std::advance(itrToRecordECC, thisRecord.recECCoffset);
+
+    checkECC(itrToRecordData, itrToRecordECC, thisRecord.recSize,
+             thisRecord.recECCLength);
+}
+
 void EditorImpl::checkECC(Binary::const_iterator& itrToRecData,
                           Binary::const_iterator& itrToECCData,
                           RecordLength recLength, ECCLength eccLength)
@@ -222,9 +234,33 @@
         vpdecc_check_data(const_cast<uint8_t*>(&itrToRecData[0]), recLength,
                           const_cast<uint8_t*>(&itrToECCData[0]), eccLength);
 
-    if (l_status != VPD_ECC_OK)
+    if (l_status == VPD_ECC_CORRECTABLE_DATA)
     {
-        throw std::runtime_error("Ecc check failed for VTOC");
+        try
+        {
+            if (vpdFileStream.is_open())
+            {
+                vpdFileStream.seekp(startOffset + thisRecord.recOffset,
+                                    std::ios::beg);
+                auto end = itrToRecData;
+                std::advance(end, recLength);
+                std::copy(itrToRecData, end,
+                          std::ostreambuf_iterator<char>(vpdFileStream));
+            }
+            else
+            {
+                throw std::runtime_error("Ecc correction failed");
+            }
+        }
+        catch (const std::fstream::failure& e)
+        {
+            std::cout << "Error while operating on file with exception";
+            throw std::runtime_error("Ecc correction failed");
+        }
+    }
+    else if (l_status != VPD_ECC_OK)
+    {
+        throw std::runtime_error("Ecc check failed");
     }
 }
 
@@ -600,8 +636,8 @@
         if (vpdType == KW_VAL_PAIR_START_TAG)
         {
             // objPath should be empty only in case of test run.
-            ParserInterface* Iparser =
-                ParserFactory::getParser(completeVPDFile, objPath);
+            ParserInterface* Iparser = ParserFactory::getParser(
+                completeVPDFile, objPath, vpdFilePath, startOffset);
             IpzVpdParser* ipzParser = dynamic_cast<IpzVpdParser*>(Iparser);
 
             try
@@ -622,6 +658,9 @@
                 // check record for keywrod
                 checkRecordForKwd();
 
+                // Check Data before updating
+                checkRecordData();
+
                 // update the data to the file
                 updateData(kwdData);
 
diff --git a/vpd-manager/editor_impl.hpp b/vpd-manager/editor_impl.hpp
index d10e157..5beedba 100644
--- a/vpd-manager/editor_impl.hpp
+++ b/vpd-manager/editor_impl.hpp
@@ -171,6 +171,9 @@
     void makeDbusCall(const std::string& object, const std::string& interface,
                       const std::string& property, const std::variant<T>& data);
 
+    /** @brief Method to check the record's Data using ECC */
+    void checkRecordData();
+
     // path to the VPD file to edit
     inventory::Path vpdFilePath;
 
@@ -180,6 +183,9 @@
     // stream to perform operation on file
     std::fstream vpdFileStream;
 
+    // stream to operate on VPD data
+    std::fstream vpdDataFileStream;
+
     // offset to get vpd data from EEPROM
     uint32_t startOffset;
 
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index 53c9ad8..5fc415e 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -168,11 +168,13 @@
     try
     {
         auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath);
+        uint32_t vpdStartOffset = 0;
         const auto& inventoryPath =
             jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"]
                 .get_ref<const nlohmann::json::string_t&>();
 
-        parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath));
+        parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath),
+                                          systemVpdFilePath, vpdStartOffset);
         auto parseResult = parser->parse();
 
         if (auto pVal = std::get_if<Store>(&parseResult))