Alter FileReader's memory management

Make it so that the FileReader allows control of the memory before
at the callsite rather than over the whole lifetime of the FileReader
object.

Change-Id: Iee418af8dfa014dcf9718e9cff549ae69e5bc569
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/util/file.h b/aos/util/file.h
index 56479ce..ddd5d47 100644
--- a/aos/util/file.h
+++ b/aos/util/file.h
@@ -6,12 +6,14 @@
 #include <sys/types.h>
 
 #include <memory>
+#include <optional>
 #include <string>
 #include <string_view>
 
 #include "absl/strings/numbers.h"
 #include "absl/types/span.h"
 #include "aos/scoped/scoped_fd.h"
+#include "flatbuffers/util.h"
 #include "glog/logging.h"
 
 namespace aos {
@@ -48,43 +50,38 @@
 // Wrapper to handle reading the contents of a file into a buffer. Meant for
 // situations where the malloc'ing of ReadFileToStringOrDie is inappropriate,
 // but where you still want to read a file.
-template <int kBufferSize = 1024>
 class FileReader {
  public:
-  FileReader(std::string_view filename)
-      : file_(open(::std::string(filename).c_str(), O_RDONLY)) {
-    PCHECK(file_.get() != -1) << ": opening " << filename;
-    memset(buffer_, 0, kBufferSize);
-  }
+  FileReader(std::string_view filename);
   // Reads the entire contents of the file into the internal buffer and returns
   // a string_view of it.
   // Note: The result may not be null-terminated.
-  std::string_view ReadContents() {
-    PCHECK(0 == lseek(file_.get(), 0, SEEK_SET));
-    const ssize_t result = read(file_.get(), buffer_, sizeof(buffer_));
-    PCHECK(result >= 0);
-    return {buffer_, static_cast<size_t>(result)};
+  absl::Span<char> ReadContents(absl::Span<char> buffer);
+  // Returns the value of the file as a string, for a fixed-length file.
+  // Returns nullopt if the result is smaller than kSize. Ignores any
+  // bytes beyond kSize.
+  template <int kSize>
+  std::optional<std::array<char, kSize>> ReadString() {
+    std::array<char, kSize> result;
+    const absl::Span<char> used_span =
+        ReadContents(absl::Span<char>(result.data(), result.size()));
+    if (used_span.size() == kSize) {
+      return result;
+    } else {
+      return std::nullopt;
+    }
   }
-  // Calls ReadContents() and attempts to convert the result into an integer, or
-  // dies trying.
-  int ReadInt() {
-    int result;
-    std::string_view contents = ReadContents();
-    CHECK(absl::SimpleAtoi(contents, &result))
-        << "Failed to parse \"" << contents << "\" as int.";
-    return result;
-  }
+  // Returns the value of the file as an integer. Crashes if it doesn't fit in a
+  // 32-bit integer. The value may start with 0x for a hex value, otherwise it
+  // must be base 10.
+  int32_t ReadInt32();
 
  private:
   aos::ScopedFD file_;
-  char buffer_[kBufferSize];
 };
 
 // Simple interface to allow opening a file for writing and then writing it
 // without any malloc's.
-// TODO(james): It may make sense to add a ReadBytes() interface here that can
-// take a memory buffer to fill, to avoid the templating required by the
-// self-managed buffer of FileReader<>.
 class FileWriter {
  public:
   // The result of an individual call to WriteBytes().