aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/ijar/ijar.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/ijar/ijar.cc')
-rw-r--r--third_party/ijar/ijar.cc292
1 files changed, 223 insertions, 69 deletions
diff --git a/third_party/ijar/ijar.cc b/third_party/ijar/ijar.cc
index 160645d7ae..a50b97037d 100644
--- a/third_party/ijar/ijar.cc
+++ b/third_party/ijar/ijar.cc
@@ -15,11 +15,11 @@
// ijar.cpp -- .jar -> _interface.jar tool.
//
+#include <errno.h>
+#include <limits.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <limits.h>
-#include <errno.h>
+#include <string.h>
#include <memory>
#include "third_party/ijar/zip.h"
@@ -31,9 +31,9 @@ bool verbose = false;
// Reads a JVM class from classdata_in (of the specified length), and
// writes out a simplified class to classdata_out, advancing the
// pointer. Returns true if the class should be kept.
-bool StripClass(u1*& classdata_out, const u1* classdata_in, size_t in_length);
+bool StripClass(u1 *&classdata_out, const u1 *classdata_in, size_t in_length);
-const char* CLASS_EXTENSION = ".class";
+const char *CLASS_EXTENSION = ".class";
const size_t CLASS_EXTENSION_LENGTH = strlen(CLASS_EXTENSION);
const char *MANIFEST_DIR_PATH = "META-INF/";
@@ -51,29 +51,34 @@ const size_t TARGET_LABEL_KEY_LENGTH = strlen(TARGET_LABEL_KEY);
const char *INJECTING_RULE_KIND_KEY = "Injecting-Rule-Kind: ";
const size_t INJECTING_RULE_KIND_KEY_LENGTH = strlen(INJECTING_RULE_KIND_KEY);
+class JarExtractorProcessor : public ZipExtractorProcessor {
+ public:
+ // Set the ZipBuilder to add the ijar class to the output zip file.
+ // This pointer should not be deleted while this class is still in use and
+ // it should be set before any call to the Process() method.
+ void SetZipBuilder(ZipBuilder *builder) { this->builder_ = builder; }
+ virtual void WriteManifest(const char *target_label,
+ const char *injecting_rule_kind) = 0;
+
+ protected:
+ // Not owned by JarStripperProcessor, see SetZipBuilder().
+ ZipBuilder *builder_;
+};
+
// ZipExtractorProcessor that select only .class file and use
// StripClass to generate an interface class, storing as a new file
// in the specified ZipBuilder.
-class JarStripperProcessor : public ZipExtractorProcessor {
+class JarStripperProcessor : public JarExtractorProcessor {
public:
JarStripperProcessor() {}
virtual ~JarStripperProcessor() {}
- virtual void Process(const char* filename, const u4 attr,
- const u1* data, const size_t size);
- virtual bool Accept(const char* filename, const u4 attr);
-
- private:
- // Not owned by JarStripperProcessor, see SetZipBuilder().
- ZipBuilder* builder;
+ virtual void Process(const char *filename, const u4 attr, const u1 *data,
+ const size_t size);
+ virtual bool Accept(const char *filename, const u4 attr);
- public:
- // Set the ZipBuilder to add the ijar class to the output zip file.
- // This pointer should not be deleted while this class is still in use and
- // it should be set before any call to the Process() method.
- void SetZipBuilder(ZipBuilder* builder) {
- this->builder = builder;
- }
+ virtual void WriteManifest(const char *target_label,
+ const char *injecting_rule_kind);
};
bool JarStripperProcessor::Accept(const char *filename, const u4 /*attr*/) {
@@ -86,8 +91,8 @@ bool JarStripperProcessor::Accept(const char *filename, const u4 /*attr*/) {
return true;
}
-static bool IsModuleInfo(const char* filename) {
- const char* slash = strrchr(filename, '/');
+static bool IsModuleInfo(const char *filename) {
+ const char *slash = strrchr(filename, '/');
if (slash == NULL) {
slash = filename;
} else {
@@ -102,36 +107,195 @@ void JarStripperProcessor::Process(const char *filename, const u4 /*attr*/,
fprintf(stderr, "INFO: StripClass: %s\n", filename);
}
if (IsModuleInfo(filename)) {
- u1* q = builder->NewFile(filename, 0);
+ u1 *q = builder_->NewFile(filename, 0);
memcpy(q, data, size);
- builder->FinishFile(size, false, true);
+ builder_->FinishFile(size, /* compress: */ false, /* compute_crc: */ true);
} else {
- u1* buf = reinterpret_cast<u1*>(malloc(size));
- u1* classdata_out = buf;
+ u1 *buf = reinterpret_cast<u1 *>(malloc(size));
+ u1 *classdata_out = buf;
if (!StripClass(buf, data, size)) {
free(classdata_out);
return;
}
- u1* q = builder->NewFile(filename, 0);
+ u1 *q = builder_->NewFile(filename, 0);
size_t out_length = buf - classdata_out;
memcpy(q, classdata_out, out_length);
- builder->FinishFile(out_length, false, true);
+ builder_->FinishFile(out_length, /* compress: */ false,
+ /* compute_crc: */ true);
free(classdata_out);
}
}
-// Copies the string into the buffer without the null terminator, returns length
-static size_t WriteStr(u1 *buf, const char *str) {
+// Copies the string into the buffer without the null terminator, returns
+// updated buffer pointer
+static u1 *WriteStr(u1 *buf, const char *str) {
size_t len = strlen(str);
memcpy(buf, str, len);
- return len;
+ return buf + len;
+}
+
+// Writes a manifest attribute including a "\r\n" line break, returns updated
+// buffer pointer.
+static u1 *WriteManifestAttr(u1 *buf, const char *key, const char *val) {
+ buf = WriteStr(buf, key);
+ buf = WriteStr(buf, val);
+ *buf++ = '\r';
+ *buf++ = '\n';
+ return buf;
+}
+
+void JarStripperProcessor::WriteManifest(const char *target_label,
+ const char *injecting_rule_kind) {
+ if (target_label == nullptr) {
+ return;
+ }
+ builder_->WriteEmptyFile(MANIFEST_DIR_PATH);
+ u1 *start = builder_->NewFile(MANIFEST_PATH, 0);
+ u1 *buf = start;
+ buf = WriteStr(buf, MANIFEST_HEADER);
+ buf = WriteManifestAttr(buf, TARGET_LABEL_KEY, target_label);
+ if (injecting_rule_kind) {
+ buf = WriteManifestAttr(buf, INJECTING_RULE_KIND_KEY, injecting_rule_kind);
+ }
+ size_t total_len = buf - start;
+ builder_->FinishFile(total_len, /* compress: */ false,
+ /* compute_crc: */ true);
+}
+
+class JarCopierProcessor : public JarExtractorProcessor {
+ public:
+ JarCopierProcessor(const char *jar) : jar_(jar) {}
+ virtual ~JarCopierProcessor() {}
+
+ virtual void Process(const char *filename, const u4 /*attr*/, const u1 *data,
+ const size_t size);
+ virtual bool Accept(const char *filename, const u4 /*attr*/);
+
+ virtual void WriteManifest(const char *target_label,
+ const char *injecting_rule_kind);
+
+ private:
+ class ManifestLocator : public ZipExtractorProcessor {
+ public:
+ ManifestLocator() : manifest_buf_(nullptr), manifest_size_(0) {}
+ virtual ~ManifestLocator() { free(manifest_buf_); }
+
+ u1 *manifest_buf_;
+ size_t manifest_size_;
+
+ virtual bool Accept(const char *filename, const u4 /*attr*/) {
+ return strcmp(filename, MANIFEST_PATH) == 0;
+ }
+
+ virtual void Process(const char * /*filename*/, const u4 /*attr*/,
+ const u1 *data, const size_t size) {
+ manifest_buf_ = (u1 *)malloc(size);
+ memmove(manifest_buf_, data, size);
+ manifest_size_ = size;
+ }
+ };
+
+ const char *jar_;
+
+ u1 *AppendTargetLabelToManifest(u1 *buf, const u1 *manifest_data,
+ const size_t size, const char *target_label,
+ const char *injecting_rule_kind);
+};
+
+void JarCopierProcessor::Process(const char *filename, const u4 /*attr*/,
+ const u1 *data, const size_t size) {
+ if (verbose) {
+ fprintf(stderr, "INFO: CopyFile: %s\n", filename);
+ }
+ // We already handled the manifest in WriteManifest
+ if (strcmp(filename, MANIFEST_DIR_PATH) == 0 ||
+ strcmp(filename, MANIFEST_PATH) == 0) {
+ return;
+ }
+ u1 *q = builder_->NewFile(filename, 0);
+ memcpy(q, data, size);
+ builder_->FinishFile(size, /* compress: */ false, /* compute_crc: */ true);
+}
+
+bool JarCopierProcessor::Accept(const char * /*filename*/, const u4 /*attr*/) {
+ return true;
+}
+
+void JarCopierProcessor::WriteManifest(const char *target_label,
+ const char *injecting_rule_kind) {
+ ManifestLocator manifest_locator;
+ std::unique_ptr<ZipExtractor> in(
+ ZipExtractor::Create(jar_, &manifest_locator));
+ in->ProcessAll();
+
+ bool wants_manifest =
+ manifest_locator.manifest_buf_ != nullptr || target_label != nullptr;
+ if (wants_manifest) {
+ builder_->WriteEmptyFile(MANIFEST_DIR_PATH);
+ u1 *start = builder_->NewFile(MANIFEST_PATH, 0);
+ u1 *buf = start;
+ // Three cases:
+ // 1. We need to merge the target label into a pre-existing manifest
+ // 2. Write a manifest from scratch with a target label
+ // 3. Copy existing manifest without adding target label
+ if (manifest_locator.manifest_buf_ != nullptr && target_label != nullptr) {
+ buf = AppendTargetLabelToManifest(buf, manifest_locator.manifest_buf_,
+ manifest_locator.manifest_size_,
+ target_label, injecting_rule_kind);
+ } else if (target_label != nullptr) {
+ buf = WriteStr(buf, MANIFEST_HEADER);
+ buf = WriteManifestAttr(buf, TARGET_LABEL_KEY, target_label);
+ if (injecting_rule_kind) {
+ buf = WriteManifestAttr(buf, INJECTING_RULE_KIND_KEY,
+ injecting_rule_kind);
+ }
+ } else {
+ memcpy(buf, manifest_locator.manifest_buf_,
+ manifest_locator.manifest_size_);
+ buf += manifest_locator.manifest_size_;
+ }
+
+ size_t total_len = buf - start;
+ builder_->FinishFile(total_len, /* compress: */ false,
+ /* compute_crc: */ true);
+ }
+}
+
+u1 *JarCopierProcessor::AppendTargetLabelToManifest(
+ u1 *buf, const u1 *manifest_data, const size_t size,
+ const char *target_label, const char *injecting_rule_kind) {
+ const char *line_start = (const char *)manifest_data;
+ const char *data_end = (const char *)manifest_data + size;
+ while (line_start < data_end) {
+ const char *line_end = strchr(line_start, '\n');
+ // Go past return char to point to next line, or to end of data buffer
+ line_end = line_end != nullptr ? line_end + 1 : data_end;
+
+ // Copy line unless it's Target-Label/Injecting-Rule-Kind and we're writing
+ // that ourselves
+ if (strncmp(line_start, TARGET_LABEL_KEY, TARGET_LABEL_KEY_LENGTH) != 0 &&
+ strncmp(line_start, INJECTING_RULE_KIND_KEY,
+ INJECTING_RULE_KIND_KEY_LENGTH) != 0) {
+ size_t len = line_end - line_start;
+ // Skip empty lines
+ if (len > 0 && line_start[0] != '\r' && line_start[0] != '\n') {
+ memcpy(buf, line_start, len);
+ buf += len;
+ }
+ }
+ line_start = line_end;
+ }
+ buf = WriteManifestAttr(buf, TARGET_LABEL_KEY, target_label);
+ if (injecting_rule_kind != nullptr) {
+ buf = WriteManifestAttr(buf, INJECTING_RULE_KIND_KEY, injecting_rule_kind);
+ }
+ return buf;
}
-// Computes the size of zip file content for the manifest created by
// WriteManifest, including zip file format overhead.
static size_t EstimateManifestOutputSize(const char *target_label,
const char *injecting_rule_kind) {
- if (target_label == NULL) {
+ if (target_label == nullptr) {
return 0;
}
// local headers
@@ -152,36 +316,21 @@ static size_t EstimateManifestOutputSize(const char *target_label,
return length;
}
-static void WriteManifest(ZipBuilder *out, const char *target_label,
- const char *injecting_rule_kind) {
- if (target_label == NULL) {
- return;
- }
- out->WriteEmptyFile(MANIFEST_DIR_PATH);
- u1 *start = out->NewFile(MANIFEST_PATH, 0);
- u1 *buf = start;
- buf += WriteStr(buf, MANIFEST_HEADER);
- buf += WriteStr(buf, TARGET_LABEL_KEY);
- buf += WriteStr(buf, target_label);
- *buf++ = '\r';
- *buf++ = '\n';
- if (injecting_rule_kind) {
- buf += WriteStr(buf, INJECTING_RULE_KIND_KEY);
- buf += WriteStr(buf, injecting_rule_kind);
- *buf++ = '\r';
- *buf++ = '\n';
- }
- size_t total_len = buf - start;
- out->FinishFile(total_len);
-}
-
// Opens "file_in" (a .jar file) for reading, and writes an interface
// .jar to "file_out".
static void OpenFilesAndProcessJar(const char *file_out, const char *file_in,
- const char *target_label,
+ bool strip_jar, const char *target_label,
const char *injecting_rule_kind) {
- JarStripperProcessor processor;
- std::unique_ptr<ZipExtractor> in(ZipExtractor::Create(file_in, &processor));
+ std::unique_ptr<JarExtractorProcessor> processor;
+ if (strip_jar) {
+ processor =
+ std::unique_ptr<JarExtractorProcessor>(new JarStripperProcessor());
+ } else {
+ processor =
+ std::unique_ptr<JarExtractorProcessor>(new JarCopierProcessor(file_in));
+ }
+ std::unique_ptr<ZipExtractor> in(
+ ZipExtractor::Create(file_in, processor.get()));
if (in.get() == NULL) {
fprintf(stderr, "Unable to open Zip file %s: %s\n", file_in,
strerror(errno));
@@ -196,9 +345,8 @@ static void OpenFilesAndProcessJar(const char *file_out, const char *file_in,
strerror(errno));
abort();
}
- processor.SetZipBuilder(out.get());
-
- WriteManifest(out.get(), target_label, injecting_rule_kind);
+ processor->SetZipBuilder(out.get());
+ processor->WriteManifest(target_label, injecting_rule_kind);
// Process all files in the zip
if (in->ProcessAll() < 0) {
@@ -219,9 +367,8 @@ static void OpenFilesAndProcessJar(const char *file_out, const char *file_in,
size_t in_length = in->GetSize();
size_t out_length = out->GetSize();
if (verbose) {
- fprintf(stderr, "INFO: produced interface jar: %s -> %s (%d%%).\n",
- file_in, file_out,
- static_cast<int>(100.0 * out_length / in_length));
+ fprintf(stderr, "INFO: produced interface jar: %s -> %s (%d%%).\n", file_in,
+ file_out, static_cast<int>(100.0 * out_length / in_length));
}
}
} // namespace devtools_ijar
@@ -232,13 +379,15 @@ static void OpenFilesAndProcessJar(const char *file_out, const char *file_in,
static void usage() {
fprintf(stderr,
"Usage: ijar "
- "[-v] [--target label label] [--injecting_rule_kind kind] "
+ "[-v] [--[no]strip_jar] "
+ "[--target label label] [--injecting_rule_kind kind] "
"x.jar [x_interface.jar>]\n");
fprintf(stderr, "Creates an interface jar from the specified jar file.\n");
exit(1);
}
int main(int argc, char **argv) {
+ bool strip_jar = true;
const char *target_label = NULL;
const char *injecting_rule_kind = NULL;
const char *filename_in = NULL;
@@ -247,6 +396,10 @@ int main(int argc, char **argv) {
for (int ii = 1; ii < argc; ++ii) {
if (strcmp(argv[ii], "-v") == 0) {
devtools_ijar::verbose = true;
+ } else if (strcmp(argv[ii], "--strip_jar") == 0) {
+ strip_jar = true;
+ } else if (strcmp(argv[ii], "--nostrip_jar") == 0) {
+ strip_jar = false;
} else if (strcmp(argv[ii], "--target_label") == 0) {
if (++ii >= argc) {
usage();
@@ -279,7 +432,8 @@ int main(int argc, char **argv) {
strcpy(filename_out_buf + len - 4, "-interface.jar");
filename_out = filename_out_buf;
} else {
- fprintf(stderr, "Can't determine output filename since input filename "
+ fprintf(stderr,
+ "Can't determine output filename since input filename "
"doesn't end with '.jar'.\n");
return 1;
}
@@ -289,7 +443,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "INFO: writing to '%s'.\n", filename_out);
}
- devtools_ijar::OpenFilesAndProcessJar(filename_out, filename_in, target_label,
- injecting_rule_kind);
+ devtools_ijar::OpenFilesAndProcessJar(filename_out, filename_in, strip_jar,
+ target_label, injecting_rule_kind);
return 0;
}