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

Print this page




 187     Map<Integer,Set<String>> pathsMap = new HashMap<>();
 188 
 189     // There's also a files array per version
 190     Map<Integer,String[]> filesMap = new HashMap<>();
 191 
 192     // Do we think this is a multi-release jar?  Set to true
 193     // if --release option found followed by at least file
 194     boolean isMultiRelease;
 195 
 196     /*
 197      * cflag: create
 198      * uflag: update
 199      * xflag: xtract
 200      * tflag: table
 201      * vflag: verbose
 202      * flag0: no zip compression (store only)
 203      * Mflag: DO NOT generate a manifest file (just ZIP)
 204      * iflag: generate jar index
 205      * nflag: Perform jar normalization at the end
 206      * pflag: preserve/don't strip leading slash and .. component from file name

 207      */
 208     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
 209 
 210     /* To support additional GNU Style informational options */
 211     enum Info {
 212         HELP(GNUStyleOptions::printHelp),
 213         COMPAT_HELP(GNUStyleOptions::printCompatHelp),
 214         USAGE_SUMMARY(GNUStyleOptions::printUsageSummary),
 215         VERSION(GNUStyleOptions::printVersion);
 216 
 217         private Consumer<PrintWriter> printFunction;
 218         Info(Consumer<PrintWriter> f) { this.printFunction = f; }
 219         void print(PrintWriter out) { printFunction.accept(out); }
 220     };
 221     Info info;
 222 

 223     /* Modular jar related options */
 224     boolean printModuleDescriptor;
 225     Version moduleVersion;
 226     Pattern modulesToHash;
 227     ModuleFinder moduleFinder = ModuleFinder.of();
 228 
 229     private static final String MODULE_INFO = "module-info.class";
 230 
 231     static final String MANIFEST_DIR = "META-INF/";
 232     static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
 233     static final String VERSION = "1.0";
 234 
 235     private static ResourceBundle rsrc;
 236 
 237     /**
 238      * If true, maintain compatibility with JDK releases prior to 6.0 by
 239      * timestamping extracted files with the time at which they are extracted.
 240      * Default is to use the time given in the archive.
 241      */
 242     private static final boolean useExtractionTime =
 243         Boolean.getBoolean("sun.tools.jar.useExtractionTime");
 244 


 492                 // latter can handle it.
 493 
 494                 String[] files = filesMapToFiles(filesMap);
 495                 if (fname != null && files != null) {
 496                     extract(fname, files);
 497                 } else {
 498                     InputStream in = (fname == null)
 499                         ? new FileInputStream(FileDescriptor.in)
 500                         : new FileInputStream(fname);
 501                     try {
 502                         if (!extract(new BufferedInputStream(in), files) && fname != null) {
 503                             extract(fname, files);
 504                         }
 505                     } finally {
 506                         in.close();
 507                     }
 508                 }
 509             } else if (iflag) {
 510                 String[] files = filesMap.get(BASE_VERSION);  // base entries only, can be null
 511                 genIndex(rootjar, files);
 512             } else if (printModuleDescriptor) {
 513                 boolean found;
 514                 if (fname != null) {
 515                     try (ZipFile zf = new ZipFile(fname)) {
 516                         found = printModuleDescriptor(zf);
 517                     }
 518                 } else {
 519                     try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
 520                         found = printModuleDescriptor(fin);
 521                     }
 522                 }
 523                 if (!found)
 524                     error(getMsg("error.module.descriptor.not.found"));
 525             }
 526         } catch (IOException e) {
 527             fatalError(e);
 528             ok = false;
 529         } catch (Error ee) {
 530             ee.printStackTrace();
 531             ok = false;
 532         } catch (Throwable t) {


 654         } catch (FileNotFoundException e) {
 655             fatalError(formatMsg("error.cant.open", e.getMessage()));
 656             return false;
 657         } catch (IOException e) {
 658             fatalError(e);
 659             return false;
 660         }
 661         /* parse flags */
 662         int count = 1;
 663         try {
 664             String flags = args[0];
 665 
 666             // Note: flags.length == 2 can be treated as the short version of
 667             // the GNU option since the there cannot be any other options,
 668             // excluding -C, as per the old way.
 669             if (flags.startsWith("--")
 670                 || (flags.startsWith("-") && flags.length() == 2)) {
 671                 try {
 672                     count = GNUStyleOptions.parseOptions(this, args);
 673                 } catch (GNUStyleOptions.BadArgs x) {
 674                     if (info != null) {
 675                         info.print(out);
 676                         return true;
 677                     }
 678                     error(x.getMessage());
 679                     if (x.showUsage)
 680                         Info.USAGE_SUMMARY.print(err);
 681                     return false;
 682                 }





 683             } else {
 684                 // Legacy/compatibility options
 685                 if (flags.startsWith("-")) {
 686                     flags = flags.substring(1);
 687                 }
 688                 for (int i = 0; i < flags.length(); i++) {
 689                     switch (flags.charAt(i)) {
 690                         case 'c':
 691                             if (xflag || tflag || uflag || iflag) {
 692                                 usageError();
 693                                 return false;
 694                             }
 695                             cflag = true;
 696                             break;
 697                         case 'u':
 698                             if (cflag || xflag || tflag || iflag) {
 699                                 usageError();
 700                                 return false;
 701                             }
 702                             uflag = true;
 703                             break;
 704                         case 'x':
 705                             if (cflag || uflag || tflag || iflag) {
 706                                 usageError();
 707                                 return false;
 708                             }
 709                             xflag = true;
 710                             break;
 711                         case 't':
 712                             if (cflag || uflag || xflag || iflag) {
 713                                 usageError();
 714                                 return false;
 715                             }
 716                             tflag = true;
 717                             break;
 718                         case 'M':
 719                             Mflag = true;
 720                             break;
 721                         case 'v':
 722                             vflag = true;
 723                             break;
 724                         case 'f':
 725                             fname = args[count++];
 726                             break;
 727                         case 'm':
 728                             mname = args[count++];
 729                             break;
 730                         case '0':
 731                             flag0 = true;
 732                             break;
 733                         case 'i':
 734                             if (cflag || uflag || xflag || tflag) {
 735                                 usageError();
 736                                 return false;
 737                             }
 738                             // do not increase the counter, files will contain rootjar
 739                             rootjar = args[count++];
 740                             iflag = true;
 741                             break;
 742                         case 'n':
 743                             nflag = true;
 744                             break;
 745                         case 'e':
 746                             ename = args[count++];
 747                             break;
 748                         case 'P':
 749                             pflag = true;
 750                             break;
 751                         default:
 752                             error(formatMsg("error.illegal.option",
 753                                     String.valueOf(flags.charAt(i))));
 754                             usageError();
 755                             return false;
 756                     }
 757                 }
 758             }
 759         } catch (ArrayIndexOutOfBoundsException e) {
 760             usageError();
 761             return false;
 762         }
 763 
 764         if (info != null) {
 765             info.print(out);
 766             return true;
 767         }
 768 
 769         if (!cflag && !tflag && !xflag && !uflag && !iflag && !printModuleDescriptor) {
 770             error(getMsg("error.bad.option"));
 771             usageError();
 772             return false;
 773         }

 774         /* parse file arguments */
 775         int n = args.length - count;
 776         if (n > 0) {
 777             if (printModuleDescriptor) {
 778                 // "--print-module-descriptor/-d" does not require file argument(s)
 779                 error(formatMsg("error.bad.dflag", args[count]));
 780                 usageError();
 781                 return false;
 782             }
 783             int version = BASE_VERSION;
 784             int k = 0;
 785             String[] nameBuf = new String[n];
 786             pathsMap.put(version, new HashSet<>());
 787             try {
 788                 for (int i = count; i < args.length; i++) {
 789                     if (args[i].equals("-C")) {
 790                         /* change the directory */
 791                         String dir = args[++i];
 792                         dir = (dir.endsWith(File.separator) ?
 793                                dir : (dir + File.separator));
 794                         dir = dir.replace(File.separatorChar, '/');
 795                         while (dir.indexOf("//") > -1) {
 796                             dir = dir.replace("//", "/");
 797                         }
 798                         pathsMap.get(version).add(dir.replace(File.separatorChar, '/'));
 799                         nameBuf[k++] = dir + args[++i];
 800                     } else if (args[i].startsWith("--release")) {
 801                         int v = BASE_VERSION;
 802                         try {
 803                             v = Integer.valueOf(args[++i]);
 804                         } catch (NumberFormatException x) {
 805                             error(formatMsg("error.release.value.notnumber", args[i]));
 806                             // this will fall into the next error, thus returning false
 807                         }
 808                         if (v < 9) {
 809                             error(formatMsg("error.release.value.toosmall", String.valueOf(v)));
 810                             usageError();
 811                             return false;
 812                         }
 813                         // associate the files, if any, with the previous version number
 814                         if (k > 0) {
 815                             String[] files = new String[k];
 816                             System.arraycopy(nameBuf, 0, files, 0, k);
 817                             filesMap.put(version, files);
 818                             isMultiRelease = version > BASE_VERSION;
 819                         }
 820                         // reset the counters and start with the new version number
 821                         k = 0;
 822                         nameBuf = new String[n];
 823                         version = v;
 824                         pathsMap.put(version, new HashSet<>());
 825                     } else {
 826                         nameBuf[k++] = args[i];
 827                     }
 828                 }
 829             } catch (ArrayIndexOutOfBoundsException e) {
 830                 usageError();
 831                 return false;
 832             }
 833             // associate remaining files, if any, with a version
 834             if (k > 0) {
 835                 String[] files = new String[k];
 836                 System.arraycopy(nameBuf, 0, files, 0, k);
 837                 filesMap.put(version, files);
 838                 isMultiRelease = version > BASE_VERSION;
 839             }
 840         } else if (cflag && (mname == null)) {
 841             error(getMsg("error.bad.cflag"));
 842             usageError();
 843             return false;
 844         } else if (uflag) {
 845             if ((mname != null) || (ename != null)) {
 846                 /* just want to update the manifest */
 847                 return true;
 848             } else {
 849                 error(getMsg("error.bad.uflag"));
 850                 usageError();
 851                 return false;
 852             }
 853         }
 854         return true;
 855     }
 856 
 857     /*
 858      * Add the package of the given resource name if it's a .class
 859      * or a resource in a named package.
 860      */
 861     boolean addPackageIfNamed(String name) {
 862         if (name.startsWith(VERSIONS_DIR)) {
 863             throw new InternalError(name);
 864         }
 865 
 866         String pn = toPackageName(name);
 867         // add if this is a class or resource in a package
 868         if (Checks.isJavaIdentifier(pn)) {
 869             packages.add(pn);
 870             return true;


1337                         javaVendor + ")");
1338         }
1339     }
1340 
1341     private void addMainClass(Manifest m, String mainApp) {
1342         Attributes global = m.getMainAttributes();
1343 
1344         // overrides any existing Main-Class attribute
1345         global.put(Attributes.Name.MAIN_CLASS, mainApp);
1346     }
1347 
1348     private void addMultiRelease(Manifest m) {
1349         Attributes global = m.getMainAttributes();
1350         global.put(Attributes.Name.MULTI_RELEASE, "true");
1351     }
1352 
1353     private boolean isAmbiguousMainClass(Manifest m) {
1354         if (ename != null) {
1355             Attributes global = m.getMainAttributes();
1356             if ((global.get(Attributes.Name.MAIN_CLASS) != null)) {
1357                 error(getMsg("error.bad.eflag"));
1358                 usageError();
1359                 return true;
1360             }
1361         }
1362         return false;
1363     }
1364 
1365     /**
1366      * Adds a new file entry to the ZIP output stream.
1367      */
1368     void addFile(ZipOutputStream zos, Entry entry) throws IOException {
1369         // skip the generation of directory entries for META-INF/versions/*/
1370         if (entry.basename.isEmpty()) return;
1371 
1372         File file = entry.file;
1373         String name = entry.entryname;
1374         boolean isDir = entry.isDir;
1375 
1376         if (name.equals("") || name.equals(".") || name.equals(zname)) {
1377             return;
1378         } else if ((name.equals(MANIFEST_DIR) || name.equals(MANIFEST_NAME))


1814      * Prints entry information.
1815      */
1816     void printEntry(ZipEntry e) throws IOException {
1817         if (vflag) {
1818             StringBuilder sb = new StringBuilder();
1819             String s = Long.toString(e.getSize());
1820             for (int i = 6 - s.length(); i > 0; --i) {
1821                 sb.append(' ');
1822             }
1823             sb.append(s).append(' ').append(new Date(e.getTime()).toString());
1824             sb.append(' ').append(e.getName());
1825             output(sb.toString());
1826         } else {
1827             output(e.getName());
1828         }
1829     }
1830 
1831     /**
1832      * Prints usage message.
1833      */
1834     void usageError() {
1835         Info.USAGE_SUMMARY.print(err);

1836     }
1837 
1838     /**
1839      * A fatal exception has been caught.  No recovery possible
1840      */
1841     void fatalError(Exception e) {
1842         e.printStackTrace();
1843     }
1844 
1845     /**
1846      * A fatal condition has been detected; message is "s".
1847      * No recovery possible
1848      */
1849     void fatalError(String s) {
1850         error(program + ": " + s);
1851     }
1852 
1853     /**
1854      * Print an output message; like verbose output and the like
1855      */




 187     Map<Integer,Set<String>> pathsMap = new HashMap<>();
 188 
 189     // There's also a files array per version
 190     Map<Integer,String[]> filesMap = new HashMap<>();
 191 
 192     // Do we think this is a multi-release jar?  Set to true
 193     // if --release option found followed by at least file
 194     boolean isMultiRelease;
 195 
 196     /*
 197      * cflag: create
 198      * uflag: update
 199      * xflag: xtract
 200      * tflag: table
 201      * vflag: verbose
 202      * flag0: no zip compression (store only)
 203      * Mflag: DO NOT generate a manifest file (just ZIP)
 204      * iflag: generate jar index
 205      * nflag: Perform jar normalization at the end
 206      * pflag: preserve/don't strip leading slash and .. component from file name
 207      * dflag: print module descriptor
 208      */
 209     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag, dflag;
 210 
 211     /* To support additional GNU Style informational options */
 212     enum Info {
 213         HELP(GNUStyleOptions::printHelp),
 214         COMPAT_HELP(GNUStyleOptions::printCompatHelp),
 215         USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp),
 216         VERSION(GNUStyleOptions::printVersion);
 217 
 218         private Consumer<PrintWriter> printFunction;
 219         Info(Consumer<PrintWriter> f) { this.printFunction = f; }
 220         void print(PrintWriter out) { printFunction.accept(out); }
 221     };
 222     Info info;
 223 
 224 
 225     /* Modular jar related options */

 226     Version moduleVersion;
 227     Pattern modulesToHash;
 228     ModuleFinder moduleFinder = ModuleFinder.of();
 229 
 230     private static final String MODULE_INFO = "module-info.class";
 231 
 232     static final String MANIFEST_DIR = "META-INF/";
 233     static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
 234     static final String VERSION = "1.0";
 235 
 236     private static ResourceBundle rsrc;
 237 
 238     /**
 239      * If true, maintain compatibility with JDK releases prior to 6.0 by
 240      * timestamping extracted files with the time at which they are extracted.
 241      * Default is to use the time given in the archive.
 242      */
 243     private static final boolean useExtractionTime =
 244         Boolean.getBoolean("sun.tools.jar.useExtractionTime");
 245 


 493                 // latter can handle it.
 494 
 495                 String[] files = filesMapToFiles(filesMap);
 496                 if (fname != null && files != null) {
 497                     extract(fname, files);
 498                 } else {
 499                     InputStream in = (fname == null)
 500                         ? new FileInputStream(FileDescriptor.in)
 501                         : new FileInputStream(fname);
 502                     try {
 503                         if (!extract(new BufferedInputStream(in), files) && fname != null) {
 504                             extract(fname, files);
 505                         }
 506                     } finally {
 507                         in.close();
 508                     }
 509                 }
 510             } else if (iflag) {
 511                 String[] files = filesMap.get(BASE_VERSION);  // base entries only, can be null
 512                 genIndex(rootjar, files);
 513             } else if (dflag) {
 514                 boolean found;
 515                 if (fname != null) {
 516                     try (ZipFile zf = new ZipFile(fname)) {
 517                         found = printModuleDescriptor(zf);
 518                     }
 519                 } else {
 520                     try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
 521                         found = printModuleDescriptor(fin);
 522                     }
 523                 }
 524                 if (!found)
 525                     error(getMsg("error.module.descriptor.not.found"));
 526             }
 527         } catch (IOException e) {
 528             fatalError(e);
 529             ok = false;
 530         } catch (Error ee) {
 531             ee.printStackTrace();
 532             ok = false;
 533         } catch (Throwable t) {


 655         } catch (FileNotFoundException e) {
 656             fatalError(formatMsg("error.cant.open", e.getMessage()));
 657             return false;
 658         } catch (IOException e) {
 659             fatalError(e);
 660             return false;
 661         }
 662         /* parse flags */
 663         int count = 1;
 664         try {
 665             String flags = args[0];
 666 
 667             // Note: flags.length == 2 can be treated as the short version of
 668             // the GNU option since the there cannot be any other options,
 669             // excluding -C, as per the old way.
 670             if (flags.startsWith("--")
 671                 || (flags.startsWith("-") && flags.length() == 2)) {
 672                 try {
 673                     count = GNUStyleOptions.parseOptions(this, args);
 674                 } catch (GNUStyleOptions.BadArgs x) {
 675                     if (info == null) {



 676                         error(x.getMessage());
 677                         if (x.showUsage)
 678                             Info.USAGE_TRYHELP.print(err);
 679                         return false;
 680                     }
 681                 }
 682                 if (info != null) {
 683                     info.print(out);
 684                     return true;
 685                 }
 686             } else {
 687                 // Legacy/compatibility options
 688                 if (flags.startsWith("-")) {
 689                     flags = flags.substring(1);
 690                 }
 691                 for (int i = 0; i < flags.length(); i++) {
 692                     switch (flags.charAt(i)) {
 693                         case 'c':
 694                             if (xflag || tflag || uflag || iflag) {
 695                                 usageError(getMsg("error.multiple.main.operations"));
 696                                 return false;
 697                             }
 698                             cflag = true;
 699                             break;
 700                         case 'u':
 701                             if (cflag || xflag || tflag || iflag) {
 702                                 usageError(getMsg("error.multiple.main.operations"));
 703                                 return false;
 704                             }
 705                             uflag = true;
 706                             break;
 707                         case 'x':
 708                             if (cflag || uflag || tflag || iflag) {
 709                                 usageError(getMsg("error.multiple.main.operations"));
 710                                 return false;
 711                             }
 712                             xflag = true;
 713                             break;
 714                         case 't':
 715                             if (cflag || uflag || xflag || iflag) {
 716                                 usageError(getMsg("error.multiple.main.operations"));
 717                                 return false;
 718                             }
 719                             tflag = true;
 720                             break;
 721                         case 'M':
 722                             Mflag = true;
 723                             break;
 724                         case 'v':
 725                             vflag = true;
 726                             break;
 727                         case 'f':
 728                             fname = args[count++];
 729                             break;
 730                         case 'm':
 731                             mname = args[count++];
 732                             break;
 733                         case '0':
 734                             flag0 = true;
 735                             break;
 736                         case 'i':
 737                             if (cflag || uflag || xflag || tflag) {
 738                                 usageError(getMsg("error.multiple.main.operations"));
 739                                 return false;
 740                             }
 741                             // do not increase the counter, files will contain rootjar
 742                             rootjar = args[count++];
 743                             iflag = true;
 744                             break;
 745                         case 'n':
 746                             nflag = true;
 747                             break;
 748                         case 'e':
 749                             ename = args[count++];
 750                             break;
 751                         case 'P':
 752                             pflag = true;
 753                             break;
 754                         default:
 755                             usageError(formatMsg("error.illegal.option",
 756                                        String.valueOf(flags.charAt(i))));

 757                             return false;
 758                     }
 759                 }
 760             }
 761         } catch (ArrayIndexOutOfBoundsException e) {
 762             usageError(getMsg("main.usage.summary"));
 763             return false;
 764         }
 765         if (!cflag && !tflag && !xflag && !uflag && !iflag && !dflag) {
 766             usageError(getMsg("error.bad.option"));







 767             return false;
 768         }
 769 
 770         /* parse file arguments */
 771         int n = args.length - count;
 772         if (n > 0) {
 773             if (dflag) {
 774                 // "--print-module-descriptor/-d" does not require file argument(s)
 775                 usageError(formatMsg("error.bad.dflag", args[count]));

 776                 return false;
 777             }
 778             int version = BASE_VERSION;
 779             int k = 0;
 780             String[] nameBuf = new String[n];
 781             pathsMap.put(version, new HashSet<>());
 782             try {
 783                 for (int i = count; i < args.length; i++) {
 784                     if (args[i].equals("-C")) {
 785                         /* change the directory */
 786                         String dir = args[++i];
 787                         dir = (dir.endsWith(File.separator) ?
 788                                dir : (dir + File.separator));
 789                         dir = dir.replace(File.separatorChar, '/');
 790                         while (dir.indexOf("//") > -1) {
 791                             dir = dir.replace("//", "/");
 792                         }
 793                         pathsMap.get(version).add(dir.replace(File.separatorChar, '/'));
 794                         nameBuf[k++] = dir + args[++i];
 795                     } else if (args[i].startsWith("--release")) {
 796                         int v = BASE_VERSION;
 797                         try {
 798                             v = Integer.valueOf(args[++i]);
 799                         } catch (NumberFormatException x) {
 800                             error(formatMsg("error.release.value.notnumber", args[i]));
 801                             // this will fall into the next error, thus returning false
 802                         }
 803                         if (v < 9) {
 804                             usageError(formatMsg("error.release.value.toosmall", String.valueOf(v)));

 805                             return false;
 806                         }
 807                         // associate the files, if any, with the previous version number
 808                         if (k > 0) {
 809                             String[] files = new String[k];
 810                             System.arraycopy(nameBuf, 0, files, 0, k);
 811                             filesMap.put(version, files);
 812                             isMultiRelease = version > BASE_VERSION;
 813                         }
 814                         // reset the counters and start with the new version number
 815                         k = 0;
 816                         nameBuf = new String[n];
 817                         version = v;
 818                         pathsMap.put(version, new HashSet<>());
 819                     } else {
 820                         nameBuf[k++] = args[i];
 821                     }
 822                 }
 823             } catch (ArrayIndexOutOfBoundsException e) {
 824                 usageError(getMsg("error.bad.file.arg"));
 825                 return false;
 826             }
 827             // associate remaining files, if any, with a version
 828             if (k > 0) {
 829                 String[] files = new String[k];
 830                 System.arraycopy(nameBuf, 0, files, 0, k);
 831                 filesMap.put(version, files);
 832                 isMultiRelease = version > BASE_VERSION;
 833             }
 834         } else if (cflag && (mname == null)) {
 835             usageError(getMsg("error.bad.cflag"));

 836             return false;
 837         } else if (uflag) {
 838             if ((mname != null) || (ename != null)) {
 839                 /* just want to update the manifest */
 840                 return true;
 841             } else {
 842                 usageError(getMsg("error.bad.uflag"));

 843                 return false;
 844             }
 845         }
 846         return true;
 847     }
 848 
 849     /*
 850      * Add the package of the given resource name if it's a .class
 851      * or a resource in a named package.
 852      */
 853     boolean addPackageIfNamed(String name) {
 854         if (name.startsWith(VERSIONS_DIR)) {
 855             throw new InternalError(name);
 856         }
 857 
 858         String pn = toPackageName(name);
 859         // add if this is a class or resource in a package
 860         if (Checks.isJavaIdentifier(pn)) {
 861             packages.add(pn);
 862             return true;


1329                         javaVendor + ")");
1330         }
1331     }
1332 
1333     private void addMainClass(Manifest m, String mainApp) {
1334         Attributes global = m.getMainAttributes();
1335 
1336         // overrides any existing Main-Class attribute
1337         global.put(Attributes.Name.MAIN_CLASS, mainApp);
1338     }
1339 
1340     private void addMultiRelease(Manifest m) {
1341         Attributes global = m.getMainAttributes();
1342         global.put(Attributes.Name.MULTI_RELEASE, "true");
1343     }
1344 
1345     private boolean isAmbiguousMainClass(Manifest m) {
1346         if (ename != null) {
1347             Attributes global = m.getMainAttributes();
1348             if ((global.get(Attributes.Name.MAIN_CLASS) != null)) {
1349                 usageError(getMsg("error.bad.eflag"));

1350                 return true;
1351             }
1352         }
1353         return false;
1354     }
1355 
1356     /**
1357      * Adds a new file entry to the ZIP output stream.
1358      */
1359     void addFile(ZipOutputStream zos, Entry entry) throws IOException {
1360         // skip the generation of directory entries for META-INF/versions/*/
1361         if (entry.basename.isEmpty()) return;
1362 
1363         File file = entry.file;
1364         String name = entry.entryname;
1365         boolean isDir = entry.isDir;
1366 
1367         if (name.equals("") || name.equals(".") || name.equals(zname)) {
1368             return;
1369         } else if ((name.equals(MANIFEST_DIR) || name.equals(MANIFEST_NAME))


1805      * Prints entry information.
1806      */
1807     void printEntry(ZipEntry e) throws IOException {
1808         if (vflag) {
1809             StringBuilder sb = new StringBuilder();
1810             String s = Long.toString(e.getSize());
1811             for (int i = 6 - s.length(); i > 0; --i) {
1812                 sb.append(' ');
1813             }
1814             sb.append(s).append(' ').append(new Date(e.getTime()).toString());
1815             sb.append(' ').append(e.getName());
1816             output(sb.toString());
1817         } else {
1818             output(e.getName());
1819         }
1820     }
1821 
1822     /**
1823      * Prints usage message.
1824      */
1825     void usageError(String s) {
1826         err.println(s);
1827         Info.USAGE_TRYHELP.print(err);
1828     }
1829 
1830     /**
1831      * A fatal exception has been caught.  No recovery possible
1832      */
1833     void fatalError(Exception e) {
1834         e.printStackTrace();
1835     }
1836 
1837     /**
1838      * A fatal condition has been detected; message is "s".
1839      * No recovery possible
1840      */
1841     void fatalError(String s) {
1842         error(program + ": " + s);
1843     }
1844 
1845     /**
1846      * Print an output message; like verbose output and the like
1847      */