1 /*
2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.tools.jar;
27
28 import java.io.*;
29 import java.nio.file.Path;
30 import java.nio.file.Files;
31 import java.util.*;
32 import java.util.zip.*;
33 import java.util.jar.*;
34 import java.util.jar.Pack200.*;
35 import java.util.jar.Manifest;
36 import java.text.MessageFormat;
37 import sun.misc.JarIndex;
38 import static sun.misc.JarIndex.INDEX_NAME;
39 import static java.util.jar.JarFile.MANIFEST_NAME;
40 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
41
42 /**
43 * This class implements a simple utility for creating files in the JAR
44 * (Java Archive) file format. The JAR format is based on the ZIP file
45 * format, with optional meta-information stored in a MANIFEST entry.
46 */
47 public
48 class Main {
49 String program;
50 PrintStream out, err;
51 String fname, mname, ename;
61 // All files need to be added/updated.
62 Set<File> entries = new LinkedHashSet<File>();
63
64 // Directories specified by "-C" operation.
65 Set<String> paths = new HashSet<String>();
66
67 /*
68 * cflag: create
69 * uflag: update
70 * xflag: xtract
71 * tflag: table
72 * vflag: verbose
73 * flag0: no zip compression (store only)
74 * Mflag: DO NOT generate a manifest file (just ZIP)
75 * iflag: generate jar index
76 * nflag: Perform jar normalization at the end
77 * pflag: preserve/don't strip leading slash and .. component from file name
78 */
79 boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
80
81 static final String MANIFEST_DIR = "META-INF/";
82 static final String VERSION = "1.0";
83
84 private static ResourceBundle rsrc;
85
86 /**
87 * If true, maintain compatibility with JDK releases prior to 6.0 by
88 * timestamping extracted files with the time at which they are extracted.
89 * Default is to use the time given in the archive.
90 */
91 private static final boolean useExtractionTime =
92 Boolean.getBoolean("sun.tools.jar.useExtractionTime");
93
94 /**
95 * Initialize ResourceBundle
96 */
97 static {
98 try {
99 rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar");
100 } catch (MissingResourceException e) {
101 throw new Error("Fatal: Resource for jar is missing");
102 }
103 }
104
105 private String getMsg(String key) {
106 try {
107 return (rsrc.getString(key));
108 } catch (MissingResourceException e) {
109 throw new Error("Error in message file");
110 }
111 }
112
113 private String formatMsg(String key, String arg) {
114 String msg = getMsg(key);
115 String[] args = new String[1];
116 args[0] = arg;
117 return MessageFormat.format(msg, (Object[]) args);
118 }
119
120 private String formatMsg2(String key, String arg, String arg1) {
121 String msg = getMsg(key);
122 String[] args = new String[2];
123 args[0] = arg;
124 args[1] = arg1;
125 return MessageFormat.format(msg, (Object[]) args);
126 }
127
128 public Main(PrintStream out, PrintStream err, String program) {
129 this.out = out;
130 this.err = err;
131 this.program = program;
132 }
133
134 /**
135 * Creates a new empty temporary file in the same directory as the
136 * specified file. A variant of File.createTempFile.
137 */
138 private static File createTempFileInSameDirectoryAs(File file)
139 throws IOException {
140 File dir = file.getParentFile();
345 }
346
347 /**
348 * Parses command line arguments.
349 */
350 boolean parseArgs(String args[]) {
351 /* Preprocess and expand @file arguments */
352 try {
353 args = CommandLine.parse(args);
354 } catch (FileNotFoundException e) {
355 fatalError(formatMsg("error.cant.open", e.getMessage()));
356 return false;
357 } catch (IOException e) {
358 fatalError(e);
359 return false;
360 }
361 /* parse flags */
362 int count = 1;
363 try {
364 String flags = args[0];
365 if (flags.startsWith("-")) {
366 flags = flags.substring(1);
367 }
368 for (int i = 0; i < flags.length(); i++) {
369 switch (flags.charAt(i)) {
370 case 'c':
371 if (xflag || tflag || uflag || iflag) {
372 usageError();
373 return false;
374 }
375 cflag = true;
376 break;
377 case 'u':
378 if (cflag || xflag || tflag || iflag) {
379 usageError();
380 return false;
381 }
382 uflag = true;
383 break;
384 case 'x':
418 // do not increase the counter, files will contain rootjar
419 rootjar = args[count++];
420 iflag = true;
421 break;
422 case 'n':
423 nflag = true;
424 break;
425 case 'e':
426 ename = args[count++];
427 break;
428 case 'P':
429 pflag = true;
430 break;
431 default:
432 error(formatMsg("error.illegal.option",
433 String.valueOf(flags.charAt(i))));
434 usageError();
435 return false;
436 }
437 }
438 } catch (ArrayIndexOutOfBoundsException e) {
439 usageError();
440 return false;
441 }
442 if (!cflag && !tflag && !xflag && !uflag && !iflag) {
443 error(getMsg("error.bad.option"));
444 usageError();
445 return false;
446 }
447 /* parse file arguments */
448 int n = args.length - count;
449 if (n > 0) {
450 int k = 0;
451 String[] nameBuf = new String[n];
452 try {
453 for (int i = count; i < args.length; i++) {
454 if (args[i].equals("-C")) {
455 /* change the directory */
456 String dir = args[++i];
457 dir = (dir.endsWith(File.separator) ?
458 dir : (dir + File.separator));
459 dir = dir.replace(File.separatorChar, '/');
460 while (dir.indexOf("//") > -1) {
461 dir = dir.replace("//", "/");
1251 */
1252 void printEntry(ZipEntry e) throws IOException {
1253 if (vflag) {
1254 StringBuilder sb = new StringBuilder();
1255 String s = Long.toString(e.getSize());
1256 for (int i = 6 - s.length(); i > 0; --i) {
1257 sb.append(' ');
1258 }
1259 sb.append(s).append(' ').append(new Date(e.getTime()).toString());
1260 sb.append(' ').append(e.getName());
1261 output(sb.toString());
1262 } else {
1263 output(e.getName());
1264 }
1265 }
1266
1267 /**
1268 * Prints usage message.
1269 */
1270 void usageError() {
1271 error(getMsg("usage"));
1272 }
1273
1274 /**
1275 * A fatal exception has been caught. No recovery possible
1276 */
1277 void fatalError(Exception e) {
1278 e.printStackTrace();
1279 }
1280
1281 /**
1282 * A fatal condition has been detected; message is "s".
1283 * No recovery possible
1284 */
1285 void fatalError(String s) {
1286 error(program + ": " + s);
1287 }
1288
1289 /**
1290 * Print an output message; like verbose output and the like
1291 */
|
1 /*
2 * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.tools.jar;
27
28 import java.io.*;
29 import java.nio.file.Path;
30 import java.nio.file.Files;
31 import java.util.*;
32 import java.util.function.Consumer;
33 import java.util.zip.*;
34 import java.util.jar.*;
35 import java.util.jar.Pack200.*;
36 import java.util.jar.Manifest;
37 import java.text.MessageFormat;
38 import sun.misc.JarIndex;
39 import static sun.misc.JarIndex.INDEX_NAME;
40 import static java.util.jar.JarFile.MANIFEST_NAME;
41 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
42
43 /**
44 * This class implements a simple utility for creating files in the JAR
45 * (Java Archive) file format. The JAR format is based on the ZIP file
46 * format, with optional meta-information stored in a MANIFEST entry.
47 */
48 public
49 class Main {
50 String program;
51 PrintStream out, err;
52 String fname, mname, ename;
62 // All files need to be added/updated.
63 Set<File> entries = new LinkedHashSet<File>();
64
65 // Directories specified by "-C" operation.
66 Set<String> paths = new HashSet<String>();
67
68 /*
69 * cflag: create
70 * uflag: update
71 * xflag: xtract
72 * tflag: table
73 * vflag: verbose
74 * flag0: no zip compression (store only)
75 * Mflag: DO NOT generate a manifest file (just ZIP)
76 * iflag: generate jar index
77 * nflag: Perform jar normalization at the end
78 * pflag: preserve/don't strip leading slash and .. component from file name
79 */
80 boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
81
82 /* To support additional GNU Style informational options */
83 enum Info {
84 HELP(GNUStyleOptions::printHelp),
85 USAGE_SUMMARY(GNUStyleOptions::printUsageSummary),
86 VERSION(GNUStyleOptions::printVersion);
87
88 private Consumer<PrintStream> printFunction;
89 Info(Consumer<PrintStream> f) { this.printFunction = f; }
90 void print(PrintStream out) { printFunction.accept(out); }
91 };
92 Info info;
93
94 static final String MANIFEST_DIR = "META-INF/";
95 static final String VERSION = "1.0";
96
97 private static ResourceBundle rsrc;
98
99 /**
100 * If true, maintain compatibility with JDK releases prior to 6.0 by
101 * timestamping extracted files with the time at which they are extracted.
102 * Default is to use the time given in the archive.
103 */
104 private static final boolean useExtractionTime =
105 Boolean.getBoolean("sun.tools.jar.useExtractionTime");
106
107 /**
108 * Initialize ResourceBundle
109 */
110 static {
111 try {
112 rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar");
113 } catch (MissingResourceException e) {
114 throw new Error("Fatal: Resource for jar is missing");
115 }
116 }
117
118 static String getMsg(String key) {
119 try {
120 return (rsrc.getString(key));
121 } catch (MissingResourceException e) {
122 throw new Error("Error in message file");
123 }
124 }
125
126 static String formatMsg(String key, String arg) {
127 String msg = getMsg(key);
128 String[] args = new String[1];
129 args[0] = arg;
130 return MessageFormat.format(msg, (Object[]) args);
131 }
132
133 static String formatMsg2(String key, String arg, String arg1) {
134 String msg = getMsg(key);
135 String[] args = new String[2];
136 args[0] = arg;
137 args[1] = arg1;
138 return MessageFormat.format(msg, (Object[]) args);
139 }
140
141 public Main(PrintStream out, PrintStream err, String program) {
142 this.out = out;
143 this.err = err;
144 this.program = program;
145 }
146
147 /**
148 * Creates a new empty temporary file in the same directory as the
149 * specified file. A variant of File.createTempFile.
150 */
151 private static File createTempFileInSameDirectoryAs(File file)
152 throws IOException {
153 File dir = file.getParentFile();
358 }
359
360 /**
361 * Parses command line arguments.
362 */
363 boolean parseArgs(String args[]) {
364 /* Preprocess and expand @file arguments */
365 try {
366 args = CommandLine.parse(args);
367 } catch (FileNotFoundException e) {
368 fatalError(formatMsg("error.cant.open", e.getMessage()));
369 return false;
370 } catch (IOException e) {
371 fatalError(e);
372 return false;
373 }
374 /* parse flags */
375 int count = 1;
376 try {
377 String flags = args[0];
378
379 // Note: flags.length == 2 can be treated as the short version
380 // of the GNU option since there cannot be any other options,
381 // excluding -C, as per the legacy options.
382 if (flags.startsWith("--")
383 || (flags.startsWith("-") && flags.length() == 2)) {
384 try {
385 count = GNUStyleOptions.parseOptions(this, args);
386 } catch (GNUStyleOptions.BadArgs x) {
387 if (info != null) {
388 info.print(out);
389 return true;
390 }
391 error(x.getMessage());
392 if (x.showUsage)
393 Info.USAGE_SUMMARY.print(err);
394 return false;
395 }
396 } else {
397 // Legacy/compatibility options
398 if (flags.startsWith("-")) {
399 flags = flags.substring(1);
400 }
401 for (int i = 0; i < flags.length(); i++) {
402 switch (flags.charAt(i)) {
403 case 'c':
404 if (xflag || tflag || uflag || iflag) {
405 usageError();
406 return false;
407 }
408 cflag = true;
409 break;
410 case 'u':
411 if (cflag || xflag || tflag || iflag) {
412 usageError();
413 return false;
414 }
415 uflag = true;
416 break;
417 case 'x':
451 // do not increase the counter, files will contain rootjar
452 rootjar = args[count++];
453 iflag = true;
454 break;
455 case 'n':
456 nflag = true;
457 break;
458 case 'e':
459 ename = args[count++];
460 break;
461 case 'P':
462 pflag = true;
463 break;
464 default:
465 error(formatMsg("error.illegal.option",
466 String.valueOf(flags.charAt(i))));
467 usageError();
468 return false;
469 }
470 }
471 }
472 } catch (ArrayIndexOutOfBoundsException e) {
473 usageError();
474 return false;
475 }
476
477 if (info != null) {
478 info.print(out);
479 return true;
480 }
481
482 if (!cflag && !tflag && !xflag && !uflag && !iflag) {
483 error(getMsg("error.bad.option"));
484 usageError();
485 return false;
486 }
487 /* parse file arguments */
488 int n = args.length - count;
489 if (n > 0) {
490 int k = 0;
491 String[] nameBuf = new String[n];
492 try {
493 for (int i = count; i < args.length; i++) {
494 if (args[i].equals("-C")) {
495 /* change the directory */
496 String dir = args[++i];
497 dir = (dir.endsWith(File.separator) ?
498 dir : (dir + File.separator));
499 dir = dir.replace(File.separatorChar, '/');
500 while (dir.indexOf("//") > -1) {
501 dir = dir.replace("//", "/");
1291 */
1292 void printEntry(ZipEntry e) throws IOException {
1293 if (vflag) {
1294 StringBuilder sb = new StringBuilder();
1295 String s = Long.toString(e.getSize());
1296 for (int i = 6 - s.length(); i > 0; --i) {
1297 sb.append(' ');
1298 }
1299 sb.append(s).append(' ').append(new Date(e.getTime()).toString());
1300 sb.append(' ').append(e.getName());
1301 output(sb.toString());
1302 } else {
1303 output(e.getName());
1304 }
1305 }
1306
1307 /**
1308 * Prints usage message.
1309 */
1310 void usageError() {
1311 Info.USAGE_SUMMARY.print(err);
1312 }
1313
1314 /**
1315 * A fatal exception has been caught. No recovery possible
1316 */
1317 void fatalError(Exception e) {
1318 e.printStackTrace();
1319 }
1320
1321 /**
1322 * A fatal condition has been detected; message is "s".
1323 * No recovery possible
1324 */
1325 void fatalError(String s) {
1326 error(program + ": " + s);
1327 }
1328
1329 /**
1330 * Print an output message; like verbose output and the like
1331 */
|