PEL: Flatten PEL from objects

Now that the Generic section object has been introduced so there are
objects for every section, a flatten can be done by flattening every
object inside the PEL and the previous workaround to save the original
raw data can be removed.

This also adds a test case that uses a real PEL from a previous
generation of systems to flatten to give some better coverage than just
using hand coded PEL sections.

A side affect of this is that the PEL constructors that take the raw
data cannot take a const vector of data, as the Stream class that will
be used to read from the vector cannot take a const.  Testcases have
been updated to ensure this data is not modified.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I64ae1d1d4a742c80e14666d6b2a6e1e0efd5fd62
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index c7df5e8..eb1a368 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -5,6 +5,8 @@
 #include "section_factory.hpp"
 #include "stream.hpp"
 
+#include <phosphor-logging/log.hpp>
+
 namespace openpower
 {
 namespace pels
@@ -23,19 +25,18 @@
     _ph->sectionCount() = 2;
 }
 
-PEL::PEL(const std::vector<uint8_t>& data) : PEL(data, 0)
+PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
 {
 }
 
-PEL::PEL(const std::vector<uint8_t>& data, uint32_t obmcLogID) : _rawPEL(data)
+PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
 {
-    _fromStream = true;
-    populateFromRawData(obmcLogID);
+    populateFromRawData(data, obmcLogID);
 }
 
-void PEL::populateFromRawData(uint32_t obmcLogID)
+void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
 {
-    Stream pelData{_rawPEL};
+    Stream pelData{data};
     _ph = std::make_unique<PrivateHeader>(pelData);
     if (obmcLogID != 0)
     {
@@ -88,28 +89,26 @@
 {
     Stream pelData{pelBuffer};
 
-    _ph->flatten(pelData);
-
-    // If constructed from a PEL stream originally, don't flatten the
-    // rest of the objects until we support every PEL section type.
-    // Still need the PrivateHeader, as we updated fields in it.
-    if (_fromStream)
+    if (!valid())
     {
-        return;
+        using namespace phosphor::logging;
+        log<level::WARNING>("Unflattening an invalid PEL");
     }
 
+    _ph->flatten(pelData);
     _uh->flatten(pelData);
+
+    for (auto& section : _optionalSections)
+    {
+        section->flatten(pelData);
+    }
 }
 
 std::vector<uint8_t> PEL::data()
 {
-    // Until we can recreate a complete PEL from objects, need to just flatten
-    // on top of the original PEL data which we need to keep around for this
-    // reason.  If creating a PEL from scratch, _rawPEL will get filled in with
-    // what we do have.
-
-    flatten(_rawPEL);
-    return _rawPEL;
+    std::vector<uint8_t> pelData;
+    flatten(pelData);
+    return pelData;
 }
 
 } // namespace pels
diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp
index 29a7978..0c35e3e 100644
--- a/extensions/openpower-pels/pel.hpp
+++ b/extensions/openpower-pels/pel.hpp
@@ -32,7 +32,7 @@
  * This class represents all sections with objects.
  *
  * The available constructors are:
- * - PEL(const std::vector<uint8_t>& data) - build this object out of a fully
+ * - PEL(std::vector<uint8_t>& data) - build this object out of a fully
  *   formed flattened PEL.
  *
  * - PEL(const openpower::pels::message::Entry& entry,
@@ -59,9 +59,14 @@
      *
      * Build a PEL from raw data.
      *
+     * Note: Neither this nor the following constructor can take a const vector&
+     * because the Stream class that is used to read from the vector cannot take
+     * a const.  The alternative is to make a copy of the data, but as PELs can
+     * be up to 16KB that is undesireable.
+     *
      * @param[in] data - The PEL data
      */
-    PEL(const std::vector<uint8_t>& data);
+    PEL(std::vector<uint8_t>& data);
 
     /**
      * @brief Constructor
@@ -71,7 +76,7 @@
      * @param[in] data - the PEL data
      * @param[in] obmcLogID - the corresponding OpenBMC event log ID
      */
-    PEL(const std::vector<uint8_t>& data, uint32_t obmcLogID);
+    PEL(std::vector<uint8_t>& data, uint32_t obmcLogID);
 
     /**
      * @brief Constructor
@@ -201,10 +206,14 @@
     /**
      * @brief Builds the section objects from a PEL data buffer
      *
+     * Note: The data parameter cannot be const for the same reasons
+     * as listed in the constructor.
+     *
+     * @param[in] data - The PEL data
      * @param[in] obmcLogID - The OpenBMC event log ID to use for that
      *                        field in the Private Header.
      */
-    void populateFromRawData(uint32_t obmcLogID);
+    void populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID);
 
     /**
      * @brief Flattens the PEL objects into the buffer
@@ -224,20 +233,6 @@
     std::unique_ptr<UserHeader> _uh;
 
     /**
-     * @brief The PEL itself.
-     *
-     * This should be able to be removed when this class is able to
-     * serialize/deserialize a complete PEL from its objects, as
-     * then there will be no need to keep around the data anymore.
-     */
-    std::vector<uint8_t> _rawPEL;
-
-    /**
-     * @brief If the PEL came from a flattened data stream.
-     */
-    bool _fromStream = false;
-
-    /**
      * @brief Holds all sections by the PH and UH.
      */
     std::vector<std::unique_ptr<Section>> _optionalSections;
diff --git a/extensions/openpower-pels/repository.cpp b/extensions/openpower-pels/repository.cpp
index 0810dd4..b369706 100644
--- a/extensions/openpower-pels/repository.cpp
+++ b/extensions/openpower-pels/repository.cpp
@@ -40,7 +40,7 @@
                                       std::istreambuf_iterator<char>()};
             file.close();
 
-            PEL pel(std::move(data));
+            PEL pel{data};
             if (pel.valid())
             {
                 using pelID = LogID::Pel;