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