Implement GetFileTable command handler

Change-Id: I24c663d4d7843dad65a950c85155c6ce6a28e4bb
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/libpldmresponder/file_io.cpp b/libpldmresponder/file_io.cpp
index 50c3f1d..a6c9fae 100644
--- a/libpldmresponder/file_io.cpp
+++ b/libpldmresponder/file_io.cpp
@@ -275,5 +275,55 @@
                             offset, length, address, false);
 }
 
+Response getFileTable(const uint8_t* request, size_t payloadLength)
+{
+    uint32_t transferHandle = 0;
+    uint8_t transferFlag = 0;
+    uint8_t tableType = 0;
+
+    Response response(sizeof(pldm_msg_hdr) +
+                      PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
+    {
+        encode_get_file_table_resp(0, PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
+                                   0, responsePtr);
+        return response;
+    }
+
+    auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
+                                        &transferFlag, &tableType);
+    if (rc)
+    {
+        encode_get_file_table_resp(0, rc, 0, 0, nullptr, 0, responsePtr);
+        return response;
+    }
+
+    if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
+    {
+        encode_get_file_table_resp(0, PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
+                                   nullptr, 0, responsePtr);
+        return response;
+    }
+
+    using namespace pldm::filetable;
+    auto table = buildFileTable(FILE_TABLE_JSON);
+    auto attrTable = table();
+    response.resize(response.size() + attrTable.size());
+    responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    if (attrTable.empty())
+    {
+        encode_get_file_table_resp(0, PLDM_FILE_TABLE_UNAVAILABLE, 0, 0,
+                                   nullptr, 0, responsePtr);
+        return response;
+    }
+
+    encode_get_file_table_resp(0, PLDM_SUCCESS, 0, PLDM_START_AND_END,
+                               attrTable.data(), attrTable.size(), responsePtr);
+    return response;
+}
+
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/file_io.hpp b/libpldmresponder/file_io.hpp
index 17a6fe2..852f5de 100644
--- a/libpldmresponder/file_io.hpp
+++ b/libpldmresponder/file_io.hpp
@@ -164,5 +164,14 @@
  *  @return PLDM response message
  */
 Response writeFileFromMemory(const uint8_t* request, size_t payloadLength);
+
+/** @brief Handler for GetFileTable command
+ *
+ *  @param[in] request - pointer to PLDM request payload
+ *  @param[in] payloadLength - length of the message payload
+ *
+ *  @return PLDM response message
+ */
+Response getFileTable(const uint8_t* request, size_t payloadLength);
 } // namespace responder
 } // namespace pldm
diff --git a/test/libpldmresponder_fileio_test.cpp b/test/libpldmresponder_fileio_test.cpp
index 2c5f90e..ca2d6ec 100644
--- a/test/libpldmresponder_fileio_test.cpp
+++ b/test/libpldmresponder_fileio_test.cpp
@@ -468,3 +468,72 @@
     ASSERT_EQ(true,
               std::equal(attrTable.begin(), attrTable.end(), table.begin()));
 }
+
+TEST_F(TestFileTable, GetFileTableCommand)
+{
+    // Initialise the file table with a valid handle of 0 & 1
+    auto& table = buildFileTable(fileTableConfig.c_str());
+
+    uint32_t transferHandle = 0;
+    uint8_t opFlag = 0;
+    uint8_t type = PLDM_FILE_ATTRIBUTE_TABLE;
+    uint32_t nextTransferHandle = 0;
+    uint8_t transferFlag = PLDM_START_AND_END;
+
+    std::array<uint8_t, PLDM_GET_FILE_TABLE_REQ_BYTES> requestMsg{};
+    auto request =
+        reinterpret_cast<pldm_get_file_table_req*>(requestMsg.data());
+    request->transfer_handle = transferHandle;
+    request->operation_flag = opFlag;
+    request->table_type = type;
+
+    auto response = getFileTable(requestMsg.data(), requestMsg.size());
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
+    size_t offsetSize = sizeof(responsePtr->payload[0]);
+    ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &nextTransferHandle,
+                        sizeof(nextTransferHandle)));
+    offsetSize += sizeof(nextTransferHandle);
+    ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &transferFlag,
+                        sizeof(transferFlag)));
+    offsetSize += sizeof(transferFlag);
+    ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, attrTable.data(),
+                        attrTable.size()));
+    table.clear();
+}
+
+TEST_F(TestFileTable, GetFileTableCommandReqLengthMismatch)
+{
+    std::array<uint8_t, PLDM_GET_FILE_TABLE_REQ_BYTES> requestMsg{};
+
+    // Pass invalid command payload length
+    auto response = getFileTable(requestMsg.data(), 0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST_F(TestFileTable, GetFileTableCommandBufferNull)
+{
+    // Pass null buffer for payload
+    auto response = getFileTable(nullptr, PLDM_GET_FILE_TABLE_REQ_BYTES);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_DATA);
+}
+
+TEST_F(TestFileTable, GetFileTableCommandOEMAttrTable)
+{
+    uint32_t transferHandle = 0;
+    uint8_t opFlag = 0;
+    uint8_t type = PLDM_OEM_FILE_ATTRIBUTE_TABLE;
+
+    std::array<uint8_t, PLDM_GET_FILE_TABLE_REQ_BYTES> requestMsg{};
+    auto request =
+        reinterpret_cast<pldm_get_file_table_req*>(requestMsg.data());
+    request->transfer_handle = transferHandle;
+    request->operation_flag = opFlag;
+    request->table_type = type;
+
+    auto response = getFileTable(requestMsg.data(), requestMsg.size());
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE);
+}