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.Manifest;
35 import java.text.MessageFormat;
36 import sun.misc.JarIndex;
37 import static sun.misc.JarIndex.INDEX_NAME;
38 import static java.util.jar.JarFile.MANIFEST_NAME;
39 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
40
41 /**
42 * This class implements a simple utility for creating files in the JAR
43 * (Java Archive) file format. The JAR format is based on the ZIP file
44 * format, with optional meta-information stored in a MANIFEST entry.
45 */
46 public
47 class Main {
48 String program;
49 PrintStream out, err;
50 String fname, mname, ename;
51 String zname = "";
52 String[] files;
53 String rootjar = null;
54
55 // An entryName(path)->File map generated during "expand", it helps to
56 // decide whether or not an existing entry in a jar file needs to be
57 // replaced, during the "update" operation.
58 Map<String, File> entryMap = new HashMap<String, File>();
59
60 // All files need to be added/updated.
61 Set<File> entries = new LinkedHashSet<File>();
62
63 // Directories specified by "-C" operation.
64 Set<String> paths = new HashSet<String>();
65
66 /*
67 * cflag: create
68 * uflag: update
69 * xflag: xtract
70 * tflag: table
71 * vflag: verbose
72 * flag0: no zip compression (store only)
73 * Mflag: DO NOT generate a manifest file (just ZIP)
74 * iflag: generate jar index
75 */
76 boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag;
77
78 static final String MANIFEST_DIR = "META-INF/";
79 static final String VERSION = "1.0";
80
81 private static ResourceBundle rsrc;
82
83 /**
84 * If true, maintain compatibility with JDK releases prior to 6.0 by
85 * timestamping extracted files with the time at which they are extracted.
86 * Default is to use the time given in the archive.
87 */
88 private static final boolean useExtractionTime =
89 Boolean.getBoolean("sun.tools.jar.useExtractionTime");
90
91 /**
92 * Initialize ResourceBundle
93 */
94 static {
95 try {
96 rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar");
97 } catch (MissingResourceException e) {
98 throw new Error("Fatal: Resource for jar is missing");
99 }
100 }
167 InputStream in = null;
168
169 if (!Mflag) {
170 if (mname != null) {
171 in = new FileInputStream(mname);
172 manifest = new Manifest(new BufferedInputStream(in));
173 } else {
174 manifest = new Manifest();
175 }
176 addVersion(manifest);
177 addCreatedBy(manifest);
178 if (isAmbiguousMainClass(manifest)) {
179 if (in != null) {
180 in.close();
181 }
182 return false;
183 }
184 if (ename != null) {
185 addMainClass(manifest, ename);
186 }
187 }
188 OutputStream out;
189 if (fname != null) {
190 out = new FileOutputStream(fname);
191 } else {
192 out = new FileOutputStream(FileDescriptor.out);
193 if (vflag) {
194 // Disable verbose output so that it does not appear
195 // on stdout along with file data
196 // error("Warning: -v option ignored");
197 vflag = false;
198 }
199 }
200 expand(null, files, false);
201 create(new BufferedOutputStream(out, 4096), manifest);
202 if (in != null) {
203 in.close();
204 }
205 out.close();
206 } else if (uflag) {
213 in = new FileInputStream(inputFile);
214 out = new FileOutputStream(tmpFile);
215 } else {
216 in = new FileInputStream(FileDescriptor.in);
217 out = new FileOutputStream(FileDescriptor.out);
218 vflag = false;
219 }
220 InputStream manifest = (!Mflag && (mname != null)) ?
221 (new FileInputStream(mname)) : null;
222 expand(null, files, true);
223 boolean updateOk = update(in, new BufferedOutputStream(out),
224 manifest, null);
225 if (ok) {
226 ok = updateOk;
227 }
228 in.close();
229 out.close();
230 if (manifest != null) {
231 manifest.close();
232 }
233 if (fname != null) {
234 // on Win32, we need this delete
235 inputFile.delete();
236 if (!tmpFile.renameTo(inputFile)) {
237 tmpFile.delete();
238 throw new IOException(getMsg("error.write.file"));
239 }
240 tmpFile.delete();
241 }
242 } else if (tflag) {
243 replaceFSC(files);
244 if (fname != null) {
245 list(fname, files);
246 } else {
247 InputStream in = new FileInputStream(FileDescriptor.in);
248 try{
249 list(new BufferedInputStream(in), files);
250 } finally {
251 in.close();
252 }
253 }
344 fname = args[count++];
345 break;
346 case 'm':
347 mname = args[count++];
348 break;
349 case '0':
350 flag0 = true;
351 break;
352 case 'i':
353 if (cflag || uflag || xflag || tflag) {
354 usageError();
355 return false;
356 }
357 // do not increase the counter, files will contain rootjar
358 rootjar = args[count++];
359 iflag = true;
360 break;
361 case 'e':
362 ename = args[count++];
363 break;
364 default:
365 error(formatMsg("error.illegal.option",
366 String.valueOf(flags.charAt(i))));
367 usageError();
368 return false;
369 }
370 }
371 } catch (ArrayIndexOutOfBoundsException e) {
372 usageError();
373 return false;
374 }
375 if (!cflag && !tflag && !xflag && !uflag && !iflag) {
376 error(getMsg("error.bad.option"));
377 usageError();
378 return false;
379 }
380 /* parse file arguments */
381 int n = args.length - count;
382 if (n > 0) {
383 int k = 0;
393 while (dir.indexOf("//") > -1) {
394 dir = dir.replace("//", "/");
395 }
396 paths.add(dir.replace(File.separatorChar, '/'));
397 nameBuf[k++] = dir + args[++i];
398 } else {
399 nameBuf[k++] = args[i];
400 }
401 }
402 } catch (ArrayIndexOutOfBoundsException e) {
403 usageError();
404 return false;
405 }
406 files = new String[k];
407 System.arraycopy(nameBuf, 0, files, 0, k);
408 } else if (cflag && (mname == null)) {
409 error(getMsg("error.bad.cflag"));
410 usageError();
411 return false;
412 } else if (uflag) {
413 if ((mname != null) || (ename != null)) {
414 /* just want to update the manifest */
415 return true;
416 } else {
417 error(getMsg("error.bad.uflag"));
418 usageError();
419 return false;
420 }
421 }
422 return true;
423 }
424
425 /**
426 * Expands list of files to process into full list of all files that
427 * can be found by recursively descending directories.
428 */
429 void expand(File dir, String[] files, boolean isUpdate) {
430 if (files == null) {
431 return;
432 }
433 for (int i = 0; i < files.length; i++) {
527 ZipInputStream zis = new ZipInputStream(in);
528 ZipOutputStream zos = new JarOutputStream(out);
529 ZipEntry e = null;
530 boolean foundManifest = false;
531 boolean updateOk = true;
532
533 if (jarIndex != null) {
534 addIndex(jarIndex, zos);
535 }
536
537 // put the old entries first, replace if necessary
538 while ((e = zis.getNextEntry()) != null) {
539 String name = e.getName();
540
541 boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME);
542
543 if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME))
544 || (Mflag && isManifestEntry)) {
545 continue;
546 } else if (isManifestEntry && ((newManifest != null) ||
547 (ename != null))) {
548 foundManifest = true;
549 if (newManifest != null) {
550 // Don't read from the newManifest InputStream, as we
551 // might need it below, and we can't re-read the same data
552 // twice.
553 FileInputStream fis = new FileInputStream(mname);
554 boolean ambiguous = isAmbiguousMainClass(new Manifest(fis));
555 fis.close();
556 if (ambiguous) {
557 return false;
558 }
559 }
560
561 // Update the manifest.
562 Manifest old = new Manifest(zis);
563 if (newManifest != null) {
564 old.read(newManifest);
565 }
566 updateManifest(old, zos);
567 } else {
568 if (!entryMap.containsKey(name)) { // copy the old stuff
569 // do our own compression
570 ZipEntry e2 = new ZipEntry(name);
571 e2.setMethod(e.getMethod());
572 e2.setTime(e.getTime());
573 e2.setComment(e.getComment());
574 e2.setExtra(e.getExtra());
575 if (e.getMethod() == ZipEntry.STORED) {
576 e2.setSize(e.getSize());
577 e2.setCrc(e.getCrc());
578 }
579 zos.putNextEntry(e2);
580 copy(zis, zos);
581 } else { // replace with the new files
582 File f = entryMap.get(name);
583 addFile(zos, f);
584 entryMap.remove(name);
585 entries.remove(f);
586 }
587 }
588 }
589
590 // add the remaining new files
591 for (File f: entries) {
592 addFile(zos, f);
593 }
594 if (!foundManifest) {
595 if (newManifest != null) {
596 Manifest m = new Manifest(newManifest);
597 updateOk = !isAmbiguousMainClass(m);
598 if (updateOk) {
599 updateManifest(m, zos);
600 }
601 } else if (ename != null) {
602 updateManifest(new Manifest(), zos);
603 }
604 }
605 zis.close();
606 zos.close();
607 return updateOk;
608 }
609
610
611 private void addIndex(JarIndex index, ZipOutputStream zos)
612 throws IOException
613 {
614 ZipEntry e = new ZipEntry(INDEX_NAME);
615 e.setTime(System.currentTimeMillis());
616 if (flag0) {
617 CRC32OutputStream os = new CRC32OutputStream();
618 index.write(os);
619 os.updateEntry(e);
620 }
621 zos.putNextEntry(e);
622 index.write(zos);
623 zos.closeEntry();
624 }
625
626 private void updateManifest(Manifest m, ZipOutputStream zos)
627 throws IOException
628 {
629 addVersion(m);
630 addCreatedBy(m);
631 if (ename != null) {
632 addMainClass(m, ename);
633 }
634 ZipEntry e = new ZipEntry(MANIFEST_NAME);
635 e.setTime(System.currentTimeMillis());
636 if (flag0) {
637 crc32Manifest(e, m);
638 }
639 zos.putNextEntry(e);
640 m.write(zos);
641 if (vflag) {
642 output(getMsg("out.update.manifest"));
643 }
644 }
645
646
647 private String entryName(String name) {
648 name = name.replace(File.separatorChar, '/');
649 String matchPath = "";
650 for (String path : paths) {
651 if (name.startsWith(path)
652 && (path.length() > matchPath.length())) {
653 matchPath = path;
654 }
655 }
656 name = name.substring(matchPath.length());
657
658 if (name.startsWith("/")) {
659 name = name.substring(1);
660 } else if (name.startsWith("./")) {
661 name = name.substring(2);
662 }
663 return name;
668 if (global.getValue(Attributes.Name.MANIFEST_VERSION) == null) {
669 global.put(Attributes.Name.MANIFEST_VERSION, VERSION);
670 }
671 }
672
673 private void addCreatedBy(Manifest m) {
674 Attributes global = m.getMainAttributes();
675 if (global.getValue(new Attributes.Name("Created-By")) == null) {
676 String javaVendor = System.getProperty("java.vendor");
677 String jdkVersion = System.getProperty("java.version");
678 global.put(new Attributes.Name("Created-By"), jdkVersion + " (" +
679 javaVendor + ")");
680 }
681 }
682
683 private void addMainClass(Manifest m, String mainApp) {
684 Attributes global = m.getMainAttributes();
685
686 // overrides any existing Main-Class attribute
687 global.put(Attributes.Name.MAIN_CLASS, mainApp);
688 }
689
690 private boolean isAmbiguousMainClass(Manifest m) {
691 if (ename != null) {
692 Attributes global = m.getMainAttributes();
693 if ((global.get(Attributes.Name.MAIN_CLASS) != null)) {
694 error(getMsg("error.bad.eflag"));
695 usageError();
696 return true;
697 }
698 }
699 return false;
700 }
701
702 /**
703 * Adds a new file entry to the ZIP output stream.
704 */
705 void addFile(ZipOutputStream zos, File file) throws IOException {
706 String name = file.getPath();
707 boolean isDir = file.isDirectory();
|
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.Manifest;
35 import java.text.MessageFormat;
36 import sun.misc.JarIndex;
37 import static sun.misc.JarIndex.INDEX_NAME;
38 import static java.util.jar.JarFile.MANIFEST_NAME;
39 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
40
41 /**
42 * This class implements a simple utility for creating files in the JAR
43 * (Java Archive) file format. The JAR format is based on the ZIP file
44 * format, with optional meta-information stored in a MANIFEST entry.
45 */
46 public
47 class Main {
48 String program;
49 PrintStream out, err;
50 String fname, mname, ename, pname;
51 String zname = "";
52 String[] files;
53 String rootjar = null;
54
55 // An entryName(path)->File map generated during "expand", it helps to
56 // decide whether or not an existing entry in a jar file needs to be
57 // replaced, during the "update" operation.
58 Map<String, File> entryMap = new HashMap<String, File>();
59
60 // All files need to be added/updated.
61 Set<File> entries = new LinkedHashSet<File>();
62
63 // Directories specified by "-C" operation.
64 Set<String> paths = new HashSet<String>();
65
66 /*
67 * cflag: create
68 * uflag: update
69 * xflag: xtract
70 * tflag: table
71 * vflag: verbose
72 * flag0: no zip compression (store only)
73 * Mflag: DO NOT generate a manifest file (just ZIP)
74 * iflag: generate jar index
75 */
76 boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag;
77
78 static final String MANIFEST_DIR = "META-INF/";
79 static final String VERSION = "1.0";
80
81 // valid values for Profile attribute
82 private static final String[] PROFILES = { "compact1", "compact2", "compact3" };
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 }
170 InputStream in = null;
171
172 if (!Mflag) {
173 if (mname != null) {
174 in = new FileInputStream(mname);
175 manifest = new Manifest(new BufferedInputStream(in));
176 } else {
177 manifest = new Manifest();
178 }
179 addVersion(manifest);
180 addCreatedBy(manifest);
181 if (isAmbiguousMainClass(manifest)) {
182 if (in != null) {
183 in.close();
184 }
185 return false;
186 }
187 if (ename != null) {
188 addMainClass(manifest, ename);
189 }
190 if (pname != null) {
191 if (!addProfileName(manifest, pname)) {
192 if (in != null) {
193 in.close();
194 }
195 return false;
196 }
197 }
198 }
199 OutputStream out;
200 if (fname != null) {
201 out = new FileOutputStream(fname);
202 } else {
203 out = new FileOutputStream(FileDescriptor.out);
204 if (vflag) {
205 // Disable verbose output so that it does not appear
206 // on stdout along with file data
207 // error("Warning: -v option ignored");
208 vflag = false;
209 }
210 }
211 expand(null, files, false);
212 create(new BufferedOutputStream(out, 4096), manifest);
213 if (in != null) {
214 in.close();
215 }
216 out.close();
217 } else if (uflag) {
224 in = new FileInputStream(inputFile);
225 out = new FileOutputStream(tmpFile);
226 } else {
227 in = new FileInputStream(FileDescriptor.in);
228 out = new FileOutputStream(FileDescriptor.out);
229 vflag = false;
230 }
231 InputStream manifest = (!Mflag && (mname != null)) ?
232 (new FileInputStream(mname)) : null;
233 expand(null, files, true);
234 boolean updateOk = update(in, new BufferedOutputStream(out),
235 manifest, null);
236 if (ok) {
237 ok = updateOk;
238 }
239 in.close();
240 out.close();
241 if (manifest != null) {
242 manifest.close();
243 }
244 if (ok && fname != null) {
245 // on Win32, we need this delete
246 inputFile.delete();
247 if (!tmpFile.renameTo(inputFile)) {
248 tmpFile.delete();
249 throw new IOException(getMsg("error.write.file"));
250 }
251 tmpFile.delete();
252 }
253 } else if (tflag) {
254 replaceFSC(files);
255 if (fname != null) {
256 list(fname, files);
257 } else {
258 InputStream in = new FileInputStream(FileDescriptor.in);
259 try{
260 list(new BufferedInputStream(in), files);
261 } finally {
262 in.close();
263 }
264 }
355 fname = args[count++];
356 break;
357 case 'm':
358 mname = args[count++];
359 break;
360 case '0':
361 flag0 = true;
362 break;
363 case 'i':
364 if (cflag || uflag || xflag || tflag) {
365 usageError();
366 return false;
367 }
368 // do not increase the counter, files will contain rootjar
369 rootjar = args[count++];
370 iflag = true;
371 break;
372 case 'e':
373 ename = args[count++];
374 break;
375 case 'p':
376 pname = args[count++];
377 break;
378 default:
379 error(formatMsg("error.illegal.option",
380 String.valueOf(flags.charAt(i))));
381 usageError();
382 return false;
383 }
384 }
385 } catch (ArrayIndexOutOfBoundsException e) {
386 usageError();
387 return false;
388 }
389 if (!cflag && !tflag && !xflag && !uflag && !iflag) {
390 error(getMsg("error.bad.option"));
391 usageError();
392 return false;
393 }
394 /* parse file arguments */
395 int n = args.length - count;
396 if (n > 0) {
397 int k = 0;
407 while (dir.indexOf("//") > -1) {
408 dir = dir.replace("//", "/");
409 }
410 paths.add(dir.replace(File.separatorChar, '/'));
411 nameBuf[k++] = dir + args[++i];
412 } else {
413 nameBuf[k++] = args[i];
414 }
415 }
416 } catch (ArrayIndexOutOfBoundsException e) {
417 usageError();
418 return false;
419 }
420 files = new String[k];
421 System.arraycopy(nameBuf, 0, files, 0, k);
422 } else if (cflag && (mname == null)) {
423 error(getMsg("error.bad.cflag"));
424 usageError();
425 return false;
426 } else if (uflag) {
427 if ((mname != null) || (ename != null) || (pname != null)) {
428 /* just want to update the manifest */
429 return true;
430 } else {
431 error(getMsg("error.bad.uflag"));
432 usageError();
433 return false;
434 }
435 }
436 return true;
437 }
438
439 /**
440 * Expands list of files to process into full list of all files that
441 * can be found by recursively descending directories.
442 */
443 void expand(File dir, String[] files, boolean isUpdate) {
444 if (files == null) {
445 return;
446 }
447 for (int i = 0; i < files.length; i++) {
541 ZipInputStream zis = new ZipInputStream(in);
542 ZipOutputStream zos = new JarOutputStream(out);
543 ZipEntry e = null;
544 boolean foundManifest = false;
545 boolean updateOk = true;
546
547 if (jarIndex != null) {
548 addIndex(jarIndex, zos);
549 }
550
551 // put the old entries first, replace if necessary
552 while ((e = zis.getNextEntry()) != null) {
553 String name = e.getName();
554
555 boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME);
556
557 if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME))
558 || (Mflag && isManifestEntry)) {
559 continue;
560 } else if (isManifestEntry && ((newManifest != null) ||
561 (ename != null) || (pname != null))) {
562 foundManifest = true;
563 if (newManifest != null) {
564 // Don't read from the newManifest InputStream, as we
565 // might need it below, and we can't re-read the same data
566 // twice.
567 FileInputStream fis = new FileInputStream(mname);
568 boolean ambiguous = isAmbiguousMainClass(new Manifest(fis));
569 fis.close();
570 if (ambiguous) {
571 return false;
572 }
573 }
574
575 // Update the manifest.
576 Manifest old = new Manifest(zis);
577 if (newManifest != null) {
578 old.read(newManifest);
579 }
580 if (!updateManifest(old, zos)) {
581 return false;
582 }
583 } else {
584 if (!entryMap.containsKey(name)) { // copy the old stuff
585 // do our own compression
586 ZipEntry e2 = new ZipEntry(name);
587 e2.setMethod(e.getMethod());
588 e2.setTime(e.getTime());
589 e2.setComment(e.getComment());
590 e2.setExtra(e.getExtra());
591 if (e.getMethod() == ZipEntry.STORED) {
592 e2.setSize(e.getSize());
593 e2.setCrc(e.getCrc());
594 }
595 zos.putNextEntry(e2);
596 copy(zis, zos);
597 } else { // replace with the new files
598 File f = entryMap.get(name);
599 addFile(zos, f);
600 entryMap.remove(name);
601 entries.remove(f);
602 }
603 }
604 }
605
606 // add the remaining new files
607 for (File f: entries) {
608 addFile(zos, f);
609 }
610 if (!foundManifest) {
611 if (newManifest != null) {
612 Manifest m = new Manifest(newManifest);
613 updateOk = !isAmbiguousMainClass(m);
614 if (updateOk) {
615 if (!updateManifest(m, zos)) {
616 updateOk = false;
617 }
618 }
619 } else if (ename != null || pname != null) {
620 if (!updateManifest(new Manifest(), zos)) {
621 updateOk = false;
622 }
623 }
624 }
625 zis.close();
626 zos.close();
627 return updateOk;
628 }
629
630
631 private void addIndex(JarIndex index, ZipOutputStream zos)
632 throws IOException
633 {
634 ZipEntry e = new ZipEntry(INDEX_NAME);
635 e.setTime(System.currentTimeMillis());
636 if (flag0) {
637 CRC32OutputStream os = new CRC32OutputStream();
638 index.write(os);
639 os.updateEntry(e);
640 }
641 zos.putNextEntry(e);
642 index.write(zos);
643 zos.closeEntry();
644 }
645
646 private boolean updateManifest(Manifest m, ZipOutputStream zos)
647 throws IOException
648 {
649 addVersion(m);
650 addCreatedBy(m);
651 if (ename != null) {
652 addMainClass(m, ename);
653 }
654 if (pname != null) {
655 if (!addProfileName(m, pname)) {
656 return false;
657 }
658 }
659 ZipEntry e = new ZipEntry(MANIFEST_NAME);
660 e.setTime(System.currentTimeMillis());
661 if (flag0) {
662 crc32Manifest(e, m);
663 }
664 zos.putNextEntry(e);
665 m.write(zos);
666 if (vflag) {
667 output(getMsg("out.update.manifest"));
668 }
669 return true;
670 }
671
672
673 private String entryName(String name) {
674 name = name.replace(File.separatorChar, '/');
675 String matchPath = "";
676 for (String path : paths) {
677 if (name.startsWith(path)
678 && (path.length() > matchPath.length())) {
679 matchPath = path;
680 }
681 }
682 name = name.substring(matchPath.length());
683
684 if (name.startsWith("/")) {
685 name = name.substring(1);
686 } else if (name.startsWith("./")) {
687 name = name.substring(2);
688 }
689 return name;
694 if (global.getValue(Attributes.Name.MANIFEST_VERSION) == null) {
695 global.put(Attributes.Name.MANIFEST_VERSION, VERSION);
696 }
697 }
698
699 private void addCreatedBy(Manifest m) {
700 Attributes global = m.getMainAttributes();
701 if (global.getValue(new Attributes.Name("Created-By")) == null) {
702 String javaVendor = System.getProperty("java.vendor");
703 String jdkVersion = System.getProperty("java.version");
704 global.put(new Attributes.Name("Created-By"), jdkVersion + " (" +
705 javaVendor + ")");
706 }
707 }
708
709 private void addMainClass(Manifest m, String mainApp) {
710 Attributes global = m.getMainAttributes();
711
712 // overrides any existing Main-Class attribute
713 global.put(Attributes.Name.MAIN_CLASS, mainApp);
714 }
715
716 private boolean addProfileName(Manifest m, String profile) {
717 // check profile name
718 boolean found = false;
719 int i = 0;
720 while (i < PROFILES.length) {
721 if (profile.equals(PROFILES[i])) {
722 found = true;
723 break;
724 }
725 i++;
726 }
727 if (!found) {
728 error(formatMsg("error.bad.pvalue", profile));
729 return false;
730 }
731
732 // overrides any existing Profile attribute
733 Attributes global = m.getMainAttributes();
734 global.put(Attributes.Name.PROFILE, profile);
735 return true;
736 }
737
738 private boolean isAmbiguousMainClass(Manifest m) {
739 if (ename != null) {
740 Attributes global = m.getMainAttributes();
741 if ((global.get(Attributes.Name.MAIN_CLASS) != null)) {
742 error(getMsg("error.bad.eflag"));
743 usageError();
744 return true;
745 }
746 }
747 return false;
748 }
749
750 /**
751 * Adds a new file entry to the ZIP output stream.
752 */
753 void addFile(ZipOutputStream zos, File file) throws IOException {
754 String name = file.getPath();
755 boolean isDir = file.isDirectory();
|