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/app.cpp b/app.cpp
index 07dbb45..63290de 100644
--- a/app.cpp
+++ b/app.cpp
@@ -48,7 +48,9 @@
                    std::istreambuf_iterator<char>());
 
         // Parse VPD
-        IpzVpdParser ipzParser(std::move(vpd), std::string{});
+        uint32_t vpdStartOffset = 0;
+        IpzVpdParser ipzParser(std::move(vpd), std::string{}, file,
+                               vpdStartOffset);
         auto vpdStore = std::move(std::get<Store>(ipzParser.parse()));
 
         if (doDump)
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index 367f8d2..57109b6 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -1460,9 +1460,18 @@
 
         try
         {
+            uint32_t vpdStartOffset = 0;
+            for (const auto& item : js["frus"][file])
+            {
+                if (item.find("offset") != item.end())
+                {
+                    vpdStartOffset = item["offset"];
+                }
+            }
             vpdVector = getVpdDataInVector(js, file);
             ParserInterface* parser = ParserFactory::getParser(
-                vpdVector, (pimPath + baseFruInventoryPath));
+                vpdVector, (pimPath + baseFruInventoryPath), file,
+                vpdStartOffset);
             variant<KeywordVpdMap, Store> parseResult;
             parseResult = parser->parse();
 
diff --git a/impl.cpp b/impl.cpp
index a8bd694..7d51433 100644
--- a/impl.cpp
+++ b/impl.cpp
@@ -74,7 +74,7 @@
 }
 
 #ifdef IPZ_PARSER
-int Impl::vhdrEccCheck() const
+int Impl::vhdrEccCheck()
 {
     int rc = eccStatus::SUCCESS;
     auto vpdPtr = vpd.cbegin();
@@ -84,8 +84,32 @@
                           lengths::VHDR_RECORD_LENGTH,
                           const_cast<uint8_t*>(&vpdPtr[offsets::VHDR_ECC]),
                           lengths::VHDR_ECC_LENGTH);
-
-    if (l_status != VPD_ECC_OK)
+    if (l_status == VPD_ECC_CORRECTABLE_DATA)
+    {
+        try
+        {
+            if (vpdFileStream.is_open())
+            {
+                vpdFileStream.seekp(vpdStartOffset + offsets::VHDR_RECORD,
+                                    std::ios::beg);
+                vpdFileStream.write(
+                    reinterpret_cast<const char*>(&vpd[offsets::VHDR_RECORD]),
+                    lengths::VHDR_RECORD_LENGTH);
+            }
+            else
+            {
+                std::cerr << "File not open";
+                rc = eccStatus::FAILED;
+            }
+        }
+        catch (const std::fstream::failure& e)
+        {
+            std::cout << "Error while operating on file with exception:"
+                      << e.what();
+            rc = eccStatus::FAILED;
+        }
+    }
+    else if (l_status != VPD_ECC_OK)
     {
         rc = eccStatus::FAILED;
     }
@@ -93,7 +117,7 @@
     return rc;
 }
 
-int Impl::vtocEccCheck() const
+int Impl::vtocEccCheck()
 {
     int rc = eccStatus::SUCCESS;
     // Use another pointer to get ECC information from VHDR,
@@ -122,8 +146,31 @@
     auto l_status = vpdecc_check_data(
         const_cast<uint8_t*>(&vpdPtr[vtocOffset]), vtocLength,
         const_cast<uint8_t*>(&vpdPtr[vtocECCOffset]), vtocECCLength);
-
-    if (l_status != VPD_ECC_OK)
+    if (l_status == VPD_ECC_CORRECTABLE_DATA)
+    {
+        try
+        {
+            if (vpdFileStream.is_open())
+            {
+                vpdFileStream.seekp(vpdStartOffset + vtocOffset, std::ios::beg);
+                vpdFileStream.write(
+                    reinterpret_cast<const char*>(&vpdPtr[vtocOffset]),
+                    vtocLength);
+            }
+            else
+            {
+                std::cerr << "File not open";
+                rc = eccStatus::FAILED;
+            }
+        }
+        catch (const std::fstream::failure& e)
+        {
+            std::cout << "Error while operating on file with exception "
+                      << e.what();
+            rc = eccStatus::FAILED;
+        }
+    }
+    else if (l_status != VPD_ECC_OK)
     {
         rc = eccStatus::FAILED;
     }
@@ -131,7 +178,7 @@
     return rc;
 }
 
-int Impl::recordEccCheck(Binary::const_iterator iterator) const
+int Impl::recordEccCheck(Binary::const_iterator iterator)
 {
     int rc = eccStatus::SUCCESS;
 
@@ -163,7 +210,32 @@
     auto l_status = vpdecc_check_data(
         const_cast<uint8_t*>(&vpdPtr[recordOffset]), recordLength,
         const_cast<uint8_t*>(&vpdPtr[eccOffset]), eccLength);
-    if (l_status != VPD_ECC_OK)
+    if (l_status == VPD_ECC_CORRECTABLE_DATA)
+    {
+        try
+        {
+            if (vpdFileStream.is_open())
+            {
+                vpdFileStream.seekp(vpdStartOffset + recordOffset,
+                                    std::ios::beg);
+                vpdFileStream.write(
+                    reinterpret_cast<const char*>(&vpdPtr[recordOffset]),
+                    recordLength);
+            }
+            else
+            {
+                std::cerr << "File not open";
+                rc = eccStatus::FAILED;
+            }
+        }
+        catch (const std::fstream::failure& e)
+        {
+            std::cout << "Error while operating on file with exception "
+                      << e.what();
+            rc = eccStatus::FAILED;
+        }
+    }
+    else if (l_status != VPD_ECC_OK)
     {
         rc = eccStatus::FAILED;
     }
@@ -172,7 +244,7 @@
 }
 #endif
 
-void Impl::checkHeader() const
+void Impl::checkHeader()
 {
     if (vpd.empty() || (lengths::RECORD_MIN > vpd.size()))
     {
@@ -201,7 +273,7 @@
     }
 }
 
-std::size_t Impl::readTOC(Binary::const_iterator& iterator) const
+std::size_t Impl::readTOC(Binary::const_iterator& iterator)
 {
     // The offset to VTOC could be 1 or 2 bytes long
     RecordOffset vtocOffset = getVtocOffset();
@@ -244,7 +316,7 @@
 }
 
 internal::OffsetList Impl::readPT(Binary::const_iterator iterator,
-                                  std::size_t ptLength) const
+                                  std::size_t ptLength)
 {
     internal::OffsetList offsets{};
 
diff --git a/impl.hpp b/impl.hpp
index 58cb674..738549a 100644
--- a/impl.hpp
+++ b/impl.hpp
@@ -4,6 +4,7 @@
 #include "store.hpp"
 
 #include <cstddef>
+#include <fstream>
 
 namespace openpower
 {
@@ -68,10 +69,24 @@
      *
      *  @param[in] vpdBuffer - Binary VPD
      *  @param[in] path - To call out FRU in case of any PEL.
+     *  @param[in] vpdFilePath - VPD File Path
+     *  @param[in] vpdStartOffset - Start offset of VPD.
      */
-    Impl(const Binary& vpdBuffer, const std::string& path) :
-        vpd(vpdBuffer), inventoryPath(path), out{}
+    Impl(const Binary& vpdBuffer, const std::string& path,
+         const std::string& vpdFilePath, uint32_t vpdStartOffset) :
+        vpd(vpdBuffer),
+        inventoryPath(path), vpdFilePath(vpdFilePath),
+        vpdStartOffset(vpdStartOffset), out{}
     {
+        try
+        {
+            vpdFileStream.open(vpdFilePath,
+                               std::ios::in | std::ios::out | std::ios::binary);
+        }
+        catch (const std::fstream::failure& e)
+        {
+            std::cout << e.what();
+        }
     }
 
     /** @brief Run the parser on binary VPD
@@ -99,7 +114,7 @@
      *  @param[in] iterator - iterator to buffer containing VPD
      *  @returns Size of the PT keyword in VTOC
      */
-    std::size_t readTOC(Binary::const_iterator& iterator) const;
+    std::size_t readTOC(Binary::const_iterator& iterator);
 
     /** @brief Read the PT keyword contained in the VHDR record,
      *         to obtain offsets to other records in the VPD.
@@ -110,7 +125,7 @@
      *  @returns List of offsets to records in VPD
      */
     internal::OffsetList readPT(Binary::const_iterator iterator,
-                                std::size_t ptLen) const;
+                                std::size_t ptLen);
 
     /** @brief Read VPD information contained within a record
      *
@@ -143,24 +158,24 @@
     internal::KeywordMap readKeywords(Binary::const_iterator iterator);
 
     /** @brief Checks if the VHDR record is present in the VPD */
-    void checkHeader() const;
+    void checkHeader();
 
     /** @brief Checks the ECC for VHDR Record.
      *  @returns Success(0) OR corrupted data(-1)
      */
-    int vhdrEccCheck() const;
+    int vhdrEccCheck();
 
     /** @brief Checks the ECC for VTOC Record.
      *  @returns Success(0) OR corrupted data(-1)
      */
-    int vtocEccCheck() const;
+    int vtocEccCheck();
 
     /** @brief Checks the ECC for the given record.
      *
      * @param[in] iterator - iterator pointing to a record in the VPD
      * @returns Success(0) OR corrupted data(-1)
      */
-    int recordEccCheck(Binary::const_iterator iterator) const;
+    int recordEccCheck(Binary::const_iterator iterator);
 
     /** @brief This interface collects Offset of VTOC
      *  @returns VTOC Offset
@@ -173,6 +188,15 @@
     /** Inventory path to call out FRU if required */
     const std::string inventoryPath;
 
+    /** Eeprom hardware path */
+    inventory::Path vpdFilePath;
+
+    /** VPD Offset **/
+    uint32_t vpdStartOffset;
+
+    /** File stream for VPD */
+    std::fstream vpdFileStream;
+
     /** @brief parser output */
     Parsed out;
 };
diff --git a/test/ipz_parser/parser.cpp b/test/ipz_parser/parser.cpp
index 945467a..c4c7566 100644
--- a/test/ipz_parser/parser.cpp
+++ b/test/ipz_parser/parser.cpp
@@ -1,6 +1,7 @@
 #include "ipz_parser.hpp"
 
 #include <cassert>
+#include <const.hpp>
 #include <defines.hpp>
 #include <fstream>
 #include <impl.hpp>
@@ -10,6 +11,9 @@
 #include <gtest/gtest.h>
 
 using namespace openpower::vpd;
+using namespace openpower::vpd::constants;
+
+constexpr uint32_t vpdOffset = 0;
 
 TEST(IpzVpdParserApp, vpdGoodPath)
 {
@@ -37,7 +41,7 @@
         0x00, 0x52, 0x54, 0x04};
 
     // call app for this vpd
-    parser::Impl p(std::move(vpd), std::string{});
+    parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
     Store vpdStore = p.run();
 
     static const std::string record = "VINI";
@@ -65,7 +69,7 @@
     Binary vpd = {};
 
     // VPD is empty
-    parser::Impl p(std::move(vpd), std::string{});
+    parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
 
     // Expecting a throw here
     EXPECT_THROW(p.run(), std::runtime_error);
@@ -98,7 +102,7 @@
     // corrupt the VHDR
     vpd[17] = 0x00;
 
-    parser::Impl p(std::move(vpd), std::string{});
+    parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
 
     // Expecting a throw here
     EXPECT_THROW(p.run(), std::runtime_error);
@@ -131,7 +135,7 @@
     // corrupt the VTOC
     vpd[61] = 0x00;
 
-    parser::Impl p(std::move(vpd), std::string{});
+    parser::Impl p(std::move(vpd), std::string{}, systemVpdFilePath, vpdOffset);
 
     // Expecting a throw here
     EXPECT_THROW(p.run(), std::runtime_error);
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))
diff --git a/vpd-parser/ipz_parser.cpp b/vpd-parser/ipz_parser.cpp
index 4f2b30e..d923aa6 100644
--- a/vpd-parser/ipz_parser.cpp
+++ b/vpd-parser/ipz_parser.cpp
@@ -15,14 +15,14 @@
 
 std::variant<kwdVpdMap, Store> IpzVpdParser::parse()
 {
-    Impl p(vpd, inventoryPath);
+    Impl p(vpd, inventoryPath, vpdFilePath, vpdStartOffset);
     Store s = p.run();
     return s;
 }
 
 void IpzVpdParser::processHeader()
 {
-    Impl p(vpd, inventoryPath);
+    Impl p(vpd, inventoryPath, vpdFilePath, vpdStartOffset);
     p.checkVPDHeader();
 }
 
@@ -34,4 +34,4 @@
 } // namespace parser
 } // namespace ipz
 } // namespace vpd
-} // namespace openpower
+} // namespace openpower
\ No newline at end of file
diff --git a/vpd-parser/ipz_parser.hpp b/vpd-parser/ipz_parser.hpp
index 5a0865c..e431cd3 100644
--- a/vpd-parser/ipz_parser.hpp
+++ b/vpd-parser/ipz_parser.hpp
@@ -31,9 +31,16 @@
 
     /**
      * @brief Constructor
+     * @param[in] - VpdVector - vpd buffer
+     * @param[in] - path - Inventory Path
+     * @param[in] - vpdFilePath - VPD H/w path
+     * @param[in] - vpdStartOffset - VPD starting offset
      */
-    IpzVpdParser(const Binary& VpdVector, const std::string& path) :
-        vpd(VpdVector), inventoryPath(path)
+    IpzVpdParser(const Binary& VpdVector, const std::string& path,
+                 const std::string& vpdFilePath, uint32_t vpdStartOffset) :
+        vpd(VpdVector),
+        inventoryPath(path), vpdFilePath(vpdFilePath),
+        vpdStartOffset(vpdStartOffset)
     {
     }
 
@@ -63,6 +70,13 @@
 
     /*Inventory path of the FRU */
     const std::string inventoryPath;
+
+    /* VPD Path */
+    const std::string vpdFilePath;
+
+    /* Offset */
+    uint32_t vpdStartOffset;
+
 }; // class IpzVpdParser
 
 } // namespace parser
diff --git a/vpd-parser/parser_factory.cpp b/vpd-parser/parser_factory.cpp
index 1afe96a..04d4960 100644
--- a/vpd-parser/parser_factory.cpp
+++ b/vpd-parser/parser_factory.cpp
@@ -24,9 +24,9 @@
 {
 namespace factory
 {
-interface::ParserInterface*
-    ParserFactory::getParser(const Binary& vpdVector,
-                             const std::string& inventoryPath)
+interface::ParserInterface* ParserFactory::getParser(
+    const Binary& vpdVector, const std::string& inventoryPath,
+    const std::string& vpdFilePath, uint32_t vpdStartOffset)
 {
     vpdType type = vpdTypeCheck(vpdVector);
 
@@ -34,7 +34,8 @@
     {
         case IPZ_VPD:
         {
-            return new IpzVpdParser(vpdVector, inventoryPath);
+            return new IpzVpdParser(vpdVector, inventoryPath, vpdFilePath,
+                                    vpdStartOffset);
         }
 
         case KEYWORD_VPD:
diff --git a/vpd-parser/parser_factory.hpp b/vpd-parser/parser_factory.hpp
index 97a96b8..983b8fd 100644
--- a/vpd-parser/parser_factory.hpp
+++ b/vpd-parser/parser_factory.hpp
@@ -31,10 +31,13 @@
      * @brief A method to get object of concrete parser class.
      * @param[in] - vpd file to check for the type.
      * @param[in] - InventoryPath to call out FRU in case PEL is logged.
+     * @param[in] - vpdFilePath for VPD HW path.
+     * @param[in] - vpdStartOffset for starting offset of VPD.
      * @return - Pointer to concrete parser class object.
      */
     static interface::ParserInterface*
-        getParser(const Binary& vpdVector, const std::string& inventoryPath);
+        getParser(const Binary& vpdVector, const std::string& inventoryPath,
+                  const std::string& vpdFilePath, uint32_t vpdStartOffset);
 
     /**
      * @brief A method to delete the parser object.
diff --git a/vpd_tool_impl.cpp b/vpd_tool_impl.cpp
index 3926c75..753181d 100644
--- a/vpd_tool_impl.cpp
+++ b/vpd_tool_impl.cpp
@@ -50,8 +50,10 @@
 
     Binary vpdVector{};
 
+    uint32_t vpdStartOffset = 0;
     vpdVector = getVpdDataInVector(js, constants::systemVpdFilePath);
-    ParserInterface* parser = ParserFactory::getParser(vpdVector, invPath);
+    ParserInterface* parser = ParserFactory::getParser(
+        vpdVector, invPath, constants::systemVpdFilePath, vpdStartOffset);
     auto parseResult = parser->parse();
     ParserFactory::freeParser(parser);
 
@@ -579,7 +581,17 @@
     const std::string& inventoryPath =
         jsonFile["frus"][fruPath][0]["inventoryPath"];
 
-    Impl obj(completeVPDFile, (constants::pimPath + inventoryPath));
+    uint32_t vpdStartOffset = 0;
+    for (const auto& item : jsonFile["frus"][fruPath])
+    {
+        if (item.find("offset") != item.end())
+        {
+            vpdStartOffset = item["offset"];
+        }
+    }
+
+    Impl obj(completeVPDFile, (constants::pimPath + inventoryPath), fruPath,
+             vpdStartOffset);
     std::string keywordVal = obj.readKwFromHw(recordName, keyword);
 
     if (!keywordVal.empty())
@@ -1034,4 +1046,4 @@
             << "\nManufacturing reset on system vpd keywords is unsuccessful";
     }
     return 0;
-}
\ No newline at end of file
+}