1 // Copyright 2001,2007 Alan Donovan. All rights reserved.
3 // Author: Alan Donovan <adonovan@google.com>
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 // ijar.cpp -- .jar -> _interface.jar tool.
27 #include "third_party/ijar/zip.h"
29 namespace devtools_ijar
{
33 // Reads a JVM class from classdata_in (of the specified length), and
34 // writes out a simplified class to classdata_out, advancing the
36 void StripClass(u1
*&classdata_out
, const u1
*classdata_in
, size_t in_length
);
38 const char* CLASS_EXTENSION
= ".class";
39 const size_t CLASS_EXTENSION_LENGTH
= strlen(CLASS_EXTENSION
);
41 // ZipExtractorProcessor that select only .class file and use
42 // StripClass to generate an interface class, storing as a new file
43 // in the specified ZipBuilder.
44 class JarStripperProcessor
: public ZipExtractorProcessor
{
46 JarStripperProcessor() {}
47 virtual ~JarStripperProcessor() {}
49 virtual void Process(const char* filename
, const u4 attr
,
50 const u1
* data
, const size_t size
);
51 virtual bool Accept(const char* filename
, const u4 attr
);
54 // Not owned by JarStripperProcessor, see SetZipBuilder().
58 // Set the ZipBuilder to add the ijar class to the output zip file.
59 // This pointer should not be deleted while this class is still in use and
60 // it should be set before any call to the Process() method.
61 void SetZipBuilder(ZipBuilder
* builder
) {
62 this->builder
= builder
;
66 bool JarStripperProcessor::Accept(const char* filename
, const u4 attr
) {
67 ssize_t offset
= strlen(filename
) - CLASS_EXTENSION_LENGTH
;
69 return strcmp(filename
+ offset
, CLASS_EXTENSION
) == 0;
74 void JarStripperProcessor::Process(const char* filename
, const u4 attr
,
75 const u1
* data
, const size_t size
) {
77 fprintf(stderr
, "INFO: StripClass: %s\n", filename
);
79 u1
*q
= builder
->NewFile(filename
, 0);
80 u1
*classdata_out
= q
;
81 StripClass(q
, data
, size
); // actually process it
82 size_t out_length
= q
- classdata_out
;
83 builder
->FinishFile(out_length
);
86 // Opens "file_in" (a .jar file) for reading, and writes an interface
87 // .jar to "file_out".
88 void OpenFilesAndProcessJar(const char *file_out
, const char *file_in
) {
89 JarStripperProcessor processor
;
90 std::unique_ptr
<ZipExtractor
> in(ZipExtractor::Create(file_in
, &processor
));
91 if (in
.get() == NULL
) {
92 fprintf(stderr
, "Unable to open Zip file %s: %s\n", file_in
,
96 u8 output_length
= in
->CalculateOutputLength();
97 std::unique_ptr
<ZipBuilder
> out(ZipBuilder::Create(file_out
, output_length
));
98 if (out
.get() == NULL
) {
99 fprintf(stderr
, "Unable to open output file %s: %s\n", file_out
,
103 processor
.SetZipBuilder(out
.get());
105 // Process all files in the zip
106 if (in
->ProcessAll() < 0) {
107 fprintf(stderr
, "%s\n", in
->GetError());
111 // Add dummy file, since javac doesn't like truly empty jars.
112 if (out
->GetNumberFiles() == 0) {
113 out
->WriteEmptyFile("dummy");
115 // Finish writing the output file
116 if (out
->Finish() < 0) {
117 fprintf(stderr
, "%s\n", out
->GetError());
121 size_t in_length
= in
->GetSize();
122 size_t out_length
= out
->GetSize();
124 fprintf(stderr
, "INFO: produced interface jar: %s -> %s (%d%%).\n",
126 static_cast<int>(100.0 * out_length
/ in_length
));
130 } // namespace devtools_ijar
135 static void usage() {
136 fprintf(stderr
, "Usage: ijar [-v] x.jar [x_interface.jar>]\n");
137 fprintf(stderr
, "Creates an interface jar from the specified jar file.\n");
141 int main(int argc
, char **argv
) {
142 const char *filename_in
= NULL
;
143 const char *filename_out
= NULL
;
145 for (int ii
= 1; ii
< argc
; ++ii
) {
146 if (strcmp(argv
[ii
], "-v") == 0) {
147 devtools_ijar::verbose
= true;
148 } else if (filename_in
== NULL
) {
149 filename_in
= argv
[ii
];
150 } else if (filename_out
== NULL
) {
151 filename_out
= argv
[ii
];
157 if (filename_in
== NULL
) {
161 // Guess output filename from input:
162 char filename_out_buf
[PATH_MAX
];
163 if (filename_out
== NULL
) {
164 size_t len
= strlen(filename_in
);
165 if (len
> 4 && strncmp(filename_in
+ len
- 4, ".jar", 4) == 0) {
166 strcpy(filename_out_buf
, filename_in
);
167 strcpy(filename_out_buf
+ len
- 4, "-interface.jar");
168 filename_out
= filename_out_buf
;
170 fprintf(stderr
, "Can't determine output filename since input filename "
171 "doesn't end with '.jar'.\n");
176 if (devtools_ijar::verbose
) {
177 fprintf(stderr
, "INFO: writing to '%s'.\n", filename_out
);
180 devtools_ijar::OpenFilesAndProcessJar(filename_out
, filename_in
);