singlejar: add support to for reading in-memory jar data

PiperOrigin-RevId: 627812833
Change-Id: I63915df8897a37d1cbd7da4c73098f9098cc7d77
diff --git a/src/tools/singlejar/input_jar.cc b/src/tools/singlejar/input_jar.cc
index 4b3deb9..ecfbd49 100644
--- a/src/tools/singlejar/input_jar.cc
+++ b/src/tools/singlejar/input_jar.cc
@@ -14,6 +14,11 @@
 
 #include "src/tools/singlejar/input_jar.h"
 
+#include <cstddef>
+#include <string>
+
+#include "src/tools/singlejar/diag.h"
+
 bool InputJar::Open(const std::string &path) {
   if (!path_.empty()) {
     diag_errx(1, "%s:%d: This instance is already handling %s\n", __FILE__,
@@ -33,7 +38,19 @@
     mapped_file_.Close();
     return false;
   }
+  return LocateCentralDirectory(path);
+}
 
+bool InputJar::Open(const std::string &path, unsigned char *data,
+                    size_t length) {
+  if (path.empty()) {
+    diag_errx(1, "%s:%d: A non-empty path is required\n", __FILE__, __LINE__);
+  }
+  mapped_file_.MapExisting(data, data + length);
+  return LocateCentralDirectory(path);
+}
+
+bool InputJar::LocateCentralDirectory(const std::string &path) {
   // Now locate End of Central Directory (ECD) record.
   auto ecd_min = mapped_file_.end() - 65536 - sizeof(ECD);
   if (ecd_min < mapped_file_.start()) {
diff --git a/src/tools/singlejar/input_jar.h b/src/tools/singlejar/input_jar.h
index 5f7a1fc..e38191e 100644
--- a/src/tools/singlejar/input_jar.h
+++ b/src/tools/singlejar/input_jar.h
@@ -22,6 +22,8 @@
 #include <inttypes.h>
 #include <stdlib.h>
 
+#include <cstddef>
+#include <cstdint>
 #include <string>
 
 #include "src/tools/singlejar/diag.h"
@@ -51,7 +53,11 @@
 #endif
 
   // Opens the file, memory maps it and locates Central Directory.
-  bool Open(const std::string& path);
+  bool Open(const std::string &path);
+
+  // Creates an input jar from data that's already in memory.
+  // Requires a non-empty path for use in diagnostics.
+  bool Open(const std::string &path, unsigned char *data, size_t length);
 
   // Returns the next Central Directory Header or nullptr.
   const CDH *NextEntry(const LH **local_header_ptr) {
@@ -98,6 +104,8 @@
   }
 
  private:
+  bool LocateCentralDirectory(const std::string &path);
+
   std::string path_;
   MappedFile mapped_file_;
   const CDH *cdh_;  // current directory entry
diff --git a/src/tools/singlejar/input_jar_scan_entries_test.h b/src/tools/singlejar/input_jar_scan_entries_test.h
index ebb634e..112758e 100644
--- a/src/tools/singlejar/input_jar_scan_entries_test.h
+++ b/src/tools/singlejar/input_jar_scan_entries_test.h
@@ -23,8 +23,8 @@
 #include <string>
 
 #include "src/tools/singlejar/input_jar.h"
+#include "src/tools/singlejar/mapped_file.h"
 #include "src/tools/singlejar/test_util.h"
-
 #include "googletest/include/gtest/gtest.h"
 
 static const char kJar[] = "jar.jar";
@@ -274,7 +274,44 @@
   EXPECT_LE(256 * 256, file_count);
 }
 
+TYPED_TEST_P(InputJarScanEntries, BasicInMemory) {
+  ASSERT_EQ(0, chdir(getenv("TEST_TMPDIR")));
+  this->CreateBasicJar();
+  MappedFile mapped_file;
+  ASSERT_TRUE(mapped_file.Open(kJar));
+  ASSERT_TRUE(this->input_jar_->Open(
+      kJar, const_cast<unsigned char *>(mapped_file.start()),
+      mapped_file.size()));
+  const LH *lh;
+  const CDH *cdh;
+  int file_count = 0;
+  bool res1_present = false;
+  bool res2_present = false;
+  while ((cdh = this->input_jar_->NextEntry(&lh))) {
+    this->SmogCheck(cdh, lh);
+    if ('/' != lh->file_name()[lh->file_name_length() - 1]) {
+      ++file_count;
+      if (cdh->file_name_is(kRes1)) {
+        EXPECT_EQ(res1_size, cdh->uncompressed_file_size());
+        res1_present = true;
+      } else if (cdh->file_name_is(kRes2)) {
+        EXPECT_EQ(res2_size, cdh->uncompressed_file_size());
+        res2_present = true;
+      }
+    }
+  }
+
+  this->input_jar_->Close();
+  mapped_file.Close();
+  unlink(kJar);
+  EXPECT_TRUE(res1_present)
+      << "Jar file " << kJar << " lacks expected '" << kRes1 << "' file.";
+  EXPECT_TRUE(res2_present)
+      << "Jar file " << kJar << " lacks expected '" << kRes2 << "' file.";
+}
+
 REGISTER_TYPED_TEST_SUITE_P(InputJarScanEntries, OpenClose, Basic,
-                            HugeUncompressed, TestZip64, LotsOfEntries);
+                            HugeUncompressed, TestZip64, LotsOfEntries,
+                            BasicInMemory);
 
 #endif  // BAZEL_SRC_TOOLS_SINGLEJAR_INPUT_JAR_SCAN_ENTRIES_TEST_H_
diff --git a/src/tools/singlejar/mapped_file.h b/src/tools/singlejar/mapped_file.h
index 163eeee..4e1790d 100644
--- a/src/tools/singlejar/mapped_file.h
+++ b/src/tools/singlejar/mapped_file.h
@@ -15,6 +15,7 @@
 #ifndef BAZEL_SRC_TOOLS_SINGLEJAR_MAPPED_FILE_H_
 #define BAZEL_SRC_TOOLS_SINGLEJAR_MAPPED_FILE_H_ 1
 
+#include <cstddef>
 #include <string>
 
 #include "src/tools/singlejar/port.h"
@@ -36,6 +37,12 @@
 
   bool Open(const std::string &path);
 
+  bool MapExisting(unsigned char *mapped_start, unsigned char *mapped_end) {
+    mapped_start_ = mapped_start;
+    mapped_end_ = mapped_end;
+    return true;
+  }
+
   void Close();
 
   bool mapped(const void *addr) const {
@@ -60,9 +67,10 @@
 #endif
 
   size_t size() const { return mapped_end_ - mapped_start_; }
-  bool is_open() const;
 
  private:
+  bool is_open() const;
+
   unsigned char *mapped_start_;
   unsigned char *mapped_end_;
 #ifdef _WIN32