updater: Add TransferList class.

This would be the top-level class that represents and holds the info
parsed from a transfer list file.

Bug: 112151972
Test: Run recovery_unit_test and recovery_component_test on marlin.
Change-Id: I83b54df9d1411542eeeb8ef4a2db167e97f989c3
diff --git a/updater/commands.cpp b/updater/commands.cpp
index 0170863..aed6336 100644
--- a/updater/commands.cpp
+++ b/updater/commands.cpp
@@ -401,3 +401,54 @@
   }
   return os;
 }
+
+TransferList TransferList::Parse(const std::string& transfer_list_str, std::string* err) {
+  TransferList result{};
+
+  std::vector<std::string> lines = android::base::Split(transfer_list_str, "\n");
+  if (lines.size() < kTransferListHeaderLines) {
+    *err = android::base::StringPrintf("too few lines in the transfer list [%zu]", lines.size());
+    return TransferList{};
+  }
+
+  // First line in transfer list is the version number.
+  if (!android::base::ParseInt(lines[0], &result.version_, 3, 4)) {
+    *err = "unexpected transfer list version ["s + lines[0] + "]";
+    return TransferList{};
+  }
+
+  // Second line in transfer list is the total number of blocks we expect to write.
+  if (!android::base::ParseUint(lines[1], &result.total_blocks_)) {
+    *err = "unexpected block count ["s + lines[1] + "]";
+    return TransferList{};
+  }
+
+  // Third line is how many stash entries are needed simultaneously.
+  if (!android::base::ParseUint(lines[2], &result.stash_max_entries_)) {
+    return TransferList{};
+  }
+
+  // Fourth line is the maximum number of blocks that will be stashed simultaneously.
+  if (!android::base::ParseUint(lines[3], &result.stash_max_blocks_)) {
+    *err = "unexpected maximum stash blocks ["s + lines[3] + "]";
+    return TransferList{};
+  }
+
+  // Subsequent lines are all individual transfer commands.
+  for (size_t i = kTransferListHeaderLines; i < lines.size(); i++) {
+    const std::string& line = lines[i];
+    if (line.empty()) continue;
+
+    size_t cmdindex = i - kTransferListHeaderLines;
+    std::string parsing_error;
+    Command command = Command::Parse(line, cmdindex, &parsing_error);
+    if (!command) {
+      *err = android::base::StringPrintf("Failed to parse command %zu [%s]: %s", cmdindex,
+                                         line.c_str(), parsing_error.c_str());
+      return TransferList{};
+    }
+    result.commands_.push_back(command);
+  }
+
+  return result;
+}