src/jdk.jartool/share/classes/sun/tools/jar/Main.java

Print this page


   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      */