Add a helper function findFruAreaLocationAndField to
updateFRUProperty

Refactoring updateFRUProperty function and created a new helper
function findFruAreaLocationAndField. Moved this function to
fru_utils.cpp as it is common for all fru-device deamons and
avoid code duplication.

This patch is created based on suggestion on the below patch.
https://gerrit.openbmc.org/c/openbmc/entity-manager/+/51555

TESTED : Built Facebook YosemiteV2 images and loaded
on the target hardware. Verified all the fru's read and write.

Signed-off-by: Kumar Thangavel <thangavel.k@hcl.com>
Change-Id: I82265e66ea5db10003e96978979250ea45c2052d
diff --git a/src/fru_utils.cpp b/src/fru_utils.cpp
index bc59af8..e030ac8 100644
--- a/src/fru_utils.cpp
+++ b/src/fru_utils.cpp
@@ -784,3 +784,111 @@
 
     return ret;
 }
+
+// Iterate FruArea Names and find start and size of the fru area that contains
+// the propertyName and the field start location for the property. fruAreaParams
+// struct values fruAreaStart, fruAreaSize, fruAreaEnd, fieldLoc values gets
+// updated/returned if successful.
+
+bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData,
+                                 const std::string& propertyName,
+                                 struct FruArea& fruAreaParams,
+                                 size_t& fruDataIter)
+{
+    const std::vector<std::string>* fruAreaFieldNames = nullptr;
+
+    uint8_t fruAreaOffsetFieldValue = 0;
+    size_t offset = 0;
+    std::string areaName = propertyName.substr(0, propertyName.find('_'));
+    std::string propertyNamePrefix = areaName + "_";
+    auto it = std::find(fruAreaNames.begin(), fruAreaNames.end(), areaName);
+    if (it == fruAreaNames.end())
+    {
+        std::cerr << "Can't parse area name for property " << propertyName
+                  << " \n";
+        return false;
+    }
+    fruAreas fruAreaToUpdate = static_cast<fruAreas>(it - fruAreaNames.begin());
+    fruAreaOffsetFieldValue =
+        fruData[getHeaderAreaFieldOffset(fruAreaToUpdate)];
+    switch (fruAreaToUpdate)
+    {
+        case fruAreas::fruAreaChassis:
+            offset = 3; // chassis part number offset. Skip fixed first 3 bytes
+            fruAreaFieldNames = &chassisFruAreas;
+            break;
+        case fruAreas::fruAreaBoard:
+            offset = 6; // board manufacturer offset. Skip fixed first 6 bytes
+            fruAreaFieldNames = &boardFruAreas;
+            break;
+        case fruAreas::fruAreaProduct:
+            // Manufacturer name offset. Skip fixed first 3 product fru bytes
+            // i.e. version, area length and language code
+            offset = 3;
+            fruAreaFieldNames = &productFruAreas;
+            break;
+        default:
+            std::cerr << "Invalid PropertyName " << propertyName << " \n";
+            return false;
+    }
+    if (fruAreaOffsetFieldValue == 0)
+    {
+        std::cerr << "FRU Area for " << propertyName << " not present \n";
+        return false;
+    }
+
+    fruAreaParams.start = fruAreaOffsetFieldValue * fruBlockSize;
+    fruAreaParams.size = fruData[fruAreaParams.start + 1] * fruBlockSize;
+    fruAreaParams.end = fruAreaParams.start + fruAreaParams.size;
+    fruDataIter = fruAreaParams.start + offset;
+    size_t skipToFRUUpdateField = 0;
+    ssize_t fieldLength = 0;
+
+    bool found = false;
+    for (const auto& field : *fruAreaFieldNames)
+    {
+        skipToFRUUpdateField++;
+        if (propertyName == propertyNamePrefix + field)
+        {
+            found = true;
+            break;
+        }
+    }
+    if (!found)
+    {
+        std::size_t pos = propertyName.find(fruCustomFieldName);
+        if (pos == std::string::npos)
+        {
+            std::cerr << "PropertyName doesn't exist in FRU Area Vectors: "
+                      << propertyName << "\n";
+            return false;
+        }
+        std::string fieldNumStr =
+            propertyName.substr(pos + fruCustomFieldName.length());
+        size_t fieldNum = std::stoi(fieldNumStr);
+        if (fieldNum == 0)
+        {
+            std::cerr << "PropertyName not recognized: " << propertyName
+                      << "\n";
+            return false;
+        }
+        skipToFRUUpdateField += fieldNum;
+    }
+
+    for (size_t i = 1; i < skipToFRUUpdateField; i++)
+    {
+        if (fruDataIter < fruData.size())
+        {
+            fieldLength = getFieldLength(fruData[fruDataIter]);
+
+            if (fieldLength < 0)
+            {
+                break;
+            }
+            fruDataIter += 1 + fieldLength;
+        }
+    }
+    fruAreaParams.updateFieldLoc = fruDataIter;
+
+    return true;
+}