buffer: Implement "readEntry"

readEntry reads the entryHeader to figure out how much of the buffer to
read for the entry.

Tested: Unit tested

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: I390e77c088439c74d100ef4b4cb35e746facd495
diff --git a/src/buffer.cpp b/src/buffer.cpp
index 87d9fa2..fca8837 100644
--- a/src/buffer.cpp
+++ b/src/buffer.cpp
@@ -12,6 +12,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <numeric>
 #include <span>
 #include <vector>
 
@@ -170,4 +171,31 @@
     return *reinterpret_cast<struct QueueEntryHeader*>(bytesRead.data());
 }
 
+EntryPair BufferImpl::readEntry(size_t offset)
+{
+    struct QueueEntryHeader entryHeader = readEntryHeader(offset);
+
+    size_t entrySize = entryHeader.entrySize;
+
+    // wraparonudRead may throw if entrySize was bigger than the buffer or if it
+    // was not able to read all bytes, let it propagate up the stack
+    // - Use additionalBoundaryCheck parameter to tighten the boundary check
+    std::vector<uint8_t> entry =
+        wraparoundRead(offset + sizeof(struct QueueEntryHeader), entrySize,
+                       sizeof(struct QueueEntryHeader));
+
+    // Calculate the checksum
+    uint8_t* entryHeaderPtr = reinterpret_cast<uint8_t*>(&entryHeader);
+    uint8_t checksum = std::accumulate(
+        entryHeaderPtr, entryHeaderPtr + sizeof(struct QueueEntryHeader), 0);
+    checksum = std::accumulate(std::begin(entry), std::end(entry), checksum);
+    if (checksum != 0)
+    {
+        throw std::runtime_error(fmt::format(
+            "[readEntry] Checksum was '{}', expected '0'", checksum));
+    }
+
+    return {entryHeader, entry};
+}
+
 } // namespace bios_bmc_smm_error_logger