189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// Copyright 2001,2007 Alan Donovan. All rights reserved.
289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// Author: Alan Donovan <adonovan@google.com>
489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// Licensed under the Apache License, Version 2.0 (the "License");
689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// you may not use this file except in compliance with the License.
789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// You may obtain a copy of the License at
889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//    http://www.apache.org/licenses/LICENSE-2.0
1089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
1189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// Unless required by applicable law or agreed to in writing, software
1289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// distributed under the License is distributed on an "AS IS" BASIS,
1389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// See the License for the specific language governing permissions and
1589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// limitations under the License.
1689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
1789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// ijar.cpp -- .jar -> _interface.jar tool.
1889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
1989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
2089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include <stdio.h>
2189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include <string.h>
2289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include <stdlib.h>
2389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include <limits.h>
2489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include <errno.h>
2589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include <memory>
2689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
2789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji#include "zip.h"
2889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
2989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajinamespace devtools_ijar {
3089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
3189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajibool verbose = false;
3289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
3389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// Reads a JVM class from classdata_in (of the specified length), and
3489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// writes out a simplified class to classdata_out, advancing the
3589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// pointer.
3689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajivoid StripClass(u1 *&classdata_out, const u1 *classdata_in, size_t in_length);
3789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
3889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajiconst char* CLASS_EXTENSION = ".class";
3989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajiconst size_t CLASS_EXTENSION_LENGTH = strlen(CLASS_EXTENSION);
4089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
4189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// ZipExtractorProcessor that select only .class file and use
4289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// StripClass to generate an interface class, storing as a new file
4389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// in the specified ZipBuilder.
4489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajiclass JarStripperProcessor : public ZipExtractorProcessor {
4589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji public:
4689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  JarStripperProcessor() {}
4789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  virtual ~JarStripperProcessor() {}
4889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
4989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  virtual void Process(const char* filename, const u4 attr,
5089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji                       const u1* data, const size_t size);
5189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  virtual bool Accept(const char* filename, const u4 attr);
5289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
5389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji private:
5489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Not owned by JarStripperProcessor, see SetZipBuilder().
5589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  ZipBuilder* builder;
5689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
5789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji public:
5889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Set the ZipBuilder to add the ijar class to the output zip file.
5989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // This pointer should not be deleted while this class is still in use and
6089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // it should be set before any call to the Process() method.
6189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  void SetZipBuilder(ZipBuilder* builder) {
6289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    this->builder = builder;
6389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
6489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji};
6589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
6689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajibool JarStripperProcessor::Accept(const char* filename, const u4) {
6789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  ssize_t offset = strlen(filename) - CLASS_EXTENSION_LENGTH;
6889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (offset >= 0) {
6989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    return strcmp(filename + offset, CLASS_EXTENSION) == 0;
7089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
7189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  return false;
7289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji}
7389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
7489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajivoid JarStripperProcessor::Process(const char* filename, const u4,
7589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji                                   const u1* data, const size_t size) {
7689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (verbose) {
7789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "INFO: StripClass: %s\n", filename);
7889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
7989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  u1 *q = builder->NewFile(filename, 0);
8089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  u1 *classdata_out = q;
8189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  StripClass(q, data, size);  // actually process it
8289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  size_t out_length = q - classdata_out;
8389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  builder->FinishFile(out_length);
8489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji}
8589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
8689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// Opens "file_in" (a .jar file) for reading, and writes an interface
8789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// .jar to "file_out".
8889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajivoid OpenFilesAndProcessJar(const char *file_out, const char *file_in) {
8989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  JarStripperProcessor processor;
9089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  std::unique_ptr<ZipExtractor> in(ZipExtractor::Create(file_in, &processor));
9189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (in.get() == NULL) {
9289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "Unable to open Zip file %s: %s\n", file_in,
9389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji            strerror(errno));
9489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    abort();
9589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
9689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  u8 output_length = in->CalculateOutputLength();
9789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  std::unique_ptr<ZipBuilder> out(ZipBuilder::Create(file_out, output_length));
9889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (out.get() == NULL) {
9989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "Unable to open output file %s: %s\n", file_out,
10089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji            strerror(errno));
10189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    abort();
10289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
10389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  processor.SetZipBuilder(out.get());
10489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
10589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Process all files in the zip
10689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (in->ProcessAll() < 0) {
10789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "%s\n", in->GetError());
10889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    abort();
10989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
11089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
11189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Add dummy file, since javac doesn't like truly empty jars.
11289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (out->GetNumberFiles() == 0) {
11389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    out->WriteEmptyFile("dummy");
11489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
11589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Finish writing the output file
11689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (out->Finish() < 0) {
11789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "%s\n", out->GetError());
11889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    abort();
11989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
12089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Get all file size
12189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  size_t in_length = in->GetSize();
12289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  size_t out_length = out->GetSize();
12389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (verbose) {
12489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "INFO: produced interface jar: %s -> %s (%d%%).\n",
12589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji            file_in, file_out,
12689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji            static_cast<int>(100.0 * out_length / in_length));
12789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
12889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji}
12989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
13089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji}  // namespace devtools_ijar
13189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
13289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
13389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji// main method
13489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji//
13589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajistatic void usage() {
13689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  fprintf(stderr, "Usage: ijar [-v] x.jar [x_interface.jar>]\n");
13789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  fprintf(stderr, "Creates an interface jar from the specified jar file.\n");
13889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  exit(1);
13989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji}
14089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
14189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamajiint main(int argc, char **argv) {
14289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  const char *filename_in = NULL;
14389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  const char *filename_out = NULL;
14489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
14589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  for (int ii = 1; ii < argc; ++ii) {
14689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    if (strcmp(argv[ii], "-v") == 0) {
14789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      devtools_ijar::verbose = true;
14889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    } else if (filename_in == NULL) {
14989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      filename_in = argv[ii];
15089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    } else if (filename_out == NULL) {
15189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      filename_out = argv[ii];
15289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    } else {
15389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      usage();
15489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    }
15589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
15689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
15789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (filename_in == NULL) {
15889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    usage();
15989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
16089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
16189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  // Guess output filename from input:
16289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  char filename_out_buf[PATH_MAX];
16389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (filename_out == NULL) {
16489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    size_t len = strlen(filename_in);
16589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    if (len > 4 && strncmp(filename_in + len - 4, ".jar", 4) == 0) {
16689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      strcpy(filename_out_buf, filename_in);
16789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      strcpy(filename_out_buf + len - 4, "-interface.jar");
16889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      filename_out = filename_out_buf;
16989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    } else {
17089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      fprintf(stderr, "Can't determine output filename since input filename "
17189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji              "doesn't end with '.jar'.\n");
17289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji      return 1;
17389b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    }
17489b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
17589b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
17689b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  if (devtools_ijar::verbose) {
17789b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji    fprintf(stderr, "INFO: writing to '%s'.\n", filename_out);
17889b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  }
17989b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji
18089b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  devtools_ijar::OpenFilesAndProcessJar(filename_out, filename_in);
18189b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji  return 0;
18289b255ab712cb7c93e99799fb2216f81e8391730Shinichiro Hamaji}
183