1 /* 2 * Copyright (c) 1997, 2011, 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 java.util.jar; 27 28 import java.io.*; 29 import java.lang.ref.SoftReference; 30 import java.net.URL; 31 import java.util.*; 32 import java.util.stream.Stream; 33 import java.util.stream.StreamSupport; 34 import java.util.zip.*; 35 import java.security.CodeSigner; 36 import java.security.cert.Certificate; 37 import java.security.AccessController; 38 import java.security.CodeSource; 39 import sun.misc.IOUtils; 40 import sun.security.action.GetPropertyAction; 41 import sun.security.util.ManifestEntryVerifier; 42 import sun.misc.SharedSecrets; 43 44 /** 45 * The <code>JarFile</code> class is used to read the contents of a jar file 46 * from any file that can be opened with <code>java.io.RandomAccessFile</code>. 47 * It extends the class <code>java.util.zip.ZipFile</code> with support 48 * for reading an optional <code>Manifest</code> entry. The 49 * <code>Manifest</code> can be used to specify meta-information about the 50 * jar file and its entries. 51 * 52 * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor 53 * or method in this class will cause a {@link NullPointerException} to be 54 * thrown. 55 * 56 * @author David Connelly 57 * @see Manifest 58 * @see java.util.zip.ZipFile 59 * @see java.util.jar.JarEntry 60 * @since 1.2 61 */ 62 public 63 class JarFile extends ZipFile { 64 private SoftReference<Manifest> manRef; 65 private JarEntry manEntry; 66 private JarVerifier jv; 67 private boolean jvInitialized; 68 private boolean verify; 69 70 // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true) 71 private boolean hasClassPathAttribute; 72 // indicates if Profile attribute present (only valid if hasCheckedSpecialAttributes true) 73 private boolean hasProfileAttribute; 74 // true if manifest checked for special attributes 75 private volatile boolean hasCheckedSpecialAttributes; 76 77 // Set up JavaUtilJarAccess in SharedSecrets 78 static { 79 SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); 80 } 81 82 /** 83 * The JAR manifest file name. 84 */ 85 public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; 86 87 /** 88 * Creates a new <code>JarFile</code> to read from the specified 89 * file <code>name</code>. The <code>JarFile</code> will be verified if 90 * it is signed. 91 * @param name the name of the jar file to be opened for reading 92 * @throws IOException if an I/O error has occurred 93 * @throws SecurityException if access to the file is denied 94 * by the SecurityManager 95 */ 96 public JarFile(String name) throws IOException { 97 this(new File(name), true, ZipFile.OPEN_READ); 98 } 99 100 /** 101 * Creates a new <code>JarFile</code> to read from the specified 102 * file <code>name</code>. 103 * @param name the name of the jar file to be opened for reading 104 * @param verify whether or not to verify the jar file if 105 * it is signed. 106 * @throws IOException if an I/O error has occurred 107 * @throws SecurityException if access to the file is denied 108 * by the SecurityManager 109 */ 110 public JarFile(String name, boolean verify) throws IOException { 111 this(new File(name), verify, ZipFile.OPEN_READ); 112 } 113 114 /** 115 * Creates a new <code>JarFile</code> to read from the specified 116 * <code>File</code> object. The <code>JarFile</code> will be verified if 117 * it is signed. 118 * @param file the jar file to be opened for reading 119 * @throws IOException if an I/O error has occurred 120 * @throws SecurityException if access to the file is denied 121 * by the SecurityManager 122 */ 123 public JarFile(File file) throws IOException { 124 this(file, true, ZipFile.OPEN_READ); 125 } 126 127 128 /** 129 * Creates a new <code>JarFile</code> to read from the specified 130 * <code>File</code> object. 131 * @param file the jar file to be opened for reading 132 * @param verify whether or not to verify the jar file if 133 * it is signed. 134 * @throws IOException if an I/O error has occurred 135 * @throws SecurityException if access to the file is denied 136 * by the SecurityManager. 137 */ 138 public JarFile(File file, boolean verify) throws IOException { 139 this(file, verify, ZipFile.OPEN_READ); 140 } 141 142 143 /** 144 * Creates a new <code>JarFile</code> to read from the specified 145 * <code>File</code> object in the specified mode. The mode argument 146 * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>. 147 * 148 * @param file the jar file to be opened for reading 149 * @param verify whether or not to verify the jar file if 150 * it is signed. 151 * @param mode the mode in which the file is to be opened 152 * @throws IOException if an I/O error has occurred 153 * @throws IllegalArgumentException 154 * if the <tt>mode</tt> argument is invalid 155 * @throws SecurityException if access to the file is denied 156 * by the SecurityManager 157 * @since 1.3 158 */ 159 public JarFile(File file, boolean verify, int mode) throws IOException { 160 super(file, mode); 161 this.verify = verify; 162 } 163 164 /** 165 * Returns the jar file manifest, or <code>null</code> if none. 166 * 167 * @return the jar file manifest, or <code>null</code> if none 168 * 169 * @throws IllegalStateException 170 * may be thrown if the jar file has been closed 171 */ 172 public Manifest getManifest() throws IOException { 173 return getManifestFromReference(); 174 } 175 176 private Manifest getManifestFromReference() throws IOException { 177 Manifest man = manRef != null ? manRef.get() : null; 178 179 if (man == null) { 180 181 JarEntry manEntry = getManEntry(); 182 183 // If found then load the manifest 184 if (manEntry != null) { 185 if (verify) { 186 byte[] b = getBytes(manEntry); 187 man = new Manifest(new ByteArrayInputStream(b)); 188 if (!jvInitialized) { 189 jv = new JarVerifier(b); 190 } 191 } else { 192 man = new Manifest(super.getInputStream(manEntry)); 193 } 194 manRef = new SoftReference<>(man); 195 } 196 } 197 return man; 198 } 199 200 private native String[] getMetaInfEntryNames(); 201 202 /** 203 * Returns the <code>JarEntry</code> for the given entry name or 204 * <code>null</code> if not found. 205 * 206 * @param name the jar file entry name 207 * @return the <code>JarEntry</code> for the given entry name or 208 * <code>null</code> if not found. 209 * 210 * @throws IllegalStateException 211 * may be thrown if the jar file has been closed 212 * 213 * @see java.util.jar.JarEntry 214 */ 215 public JarEntry getJarEntry(String name) { 216 return (JarEntry)getEntry(name); 217 } 218 219 /** 220 * Returns the <code>ZipEntry</code> for the given entry name or 221 * <code>null</code> if not found. 222 * 223 * @param name the jar file entry name 224 * @return the <code>ZipEntry</code> for the given entry name or 225 * <code>null</code> if not found 226 * 227 * @throws IllegalStateException 228 * may be thrown if the jar file has been closed 229 * 230 * @see java.util.zip.ZipEntry 231 */ 232 public ZipEntry getEntry(String name) { 233 ZipEntry ze = super.getEntry(name); 234 if (ze != null) { 235 return new JarFileEntry(ze); 236 } 237 return null; 238 } 239 240 protected class JarEntryIterator implements Enumeration<JarEntry>, 241 Iterator<JarEntry> 242 { 243 final Iterator<ZipEntry> e = new ZipFile.ZipEntryIterator(); 244 245 public boolean hasMoreElements() { 246 return e.hasNext(); 247 } 248 249 public JarEntry nextElement() { 250 return next(); 251 } 252 253 public boolean hasNext() { 254 return e.hasNext(); 255 } 256 257 public JarEntry next() { 258 ZipEntry ze = e.next(); 259 return new JarFileEntry(ze); 260 } 261 } 262 263 /** 264 * Returns an enumeration of the zip file entries. 265 */ 266 public Enumeration<JarEntry> entries() { 267 return new JarEntryIterator(); 268 } 269 270 @Override 271 public Stream<JarEntry> stream() { 272 return StreamSupport.stream(Spliterators.spliterator( 273 new JarEntryIterator(), size(), 274 Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL)); 275 } 276 277 private class JarFileEntry extends JarEntry { 278 JarFileEntry(ZipEntry ze) { 279 super(ze); 280 } 281 public Attributes getAttributes() throws IOException { 282 Manifest man = JarFile.this.getManifest(); 283 if (man != null) { 284 return man.getAttributes(getName()); 285 } else { 286 return null; 287 } 288 } 289 public Certificate[] getCertificates() { 290 try { 291 maybeInstantiateVerifier(); 292 } catch (IOException e) { 293 throw new RuntimeException(e); 294 } 295 if (certs == null && jv != null) { 296 certs = jv.getCerts(JarFile.this, this); 297 } 298 return certs == null ? null : certs.clone(); 299 } 300 public CodeSigner[] getCodeSigners() { 301 try { 302 maybeInstantiateVerifier(); 303 } catch (IOException e) { 304 throw new RuntimeException(e); 305 } 306 if (signers == null && jv != null) { 307 signers = jv.getCodeSigners(JarFile.this, this); 308 } 309 return signers == null ? null : signers.clone(); 310 } 311 } 312 313 /* 314 * Ensures that the JarVerifier has been created if one is 315 * necessary (i.e., the jar appears to be signed.) This is done as 316 * a quick check to avoid processing of the manifest for unsigned 317 * jars. 318 */ 319 private void maybeInstantiateVerifier() throws IOException { 320 if (jv != null) { 321 return; 322 } 323 324 if (verify) { 325 String[] names = getMetaInfEntryNames(); 326 if (names != null) { 327 for (int i = 0; i < names.length; i++) { 328 String name = names[i].toUpperCase(Locale.ENGLISH); 329 if (name.endsWith(".DSA") || 330 name.endsWith(".RSA") || 331 name.endsWith(".EC") || 332 name.endsWith(".SF")) { 333 // Assume since we found a signature-related file 334 // that the jar is signed and that we therefore 335 // need a JarVerifier and Manifest 336 getManifest(); 337 return; 338 } 339 } 340 } 341 // No signature-related files; don't instantiate a 342 // verifier 343 verify = false; 344 } 345 } 346 347 348 /* 349 * Initializes the verifier object by reading all the manifest 350 * entries and passing them to the verifier. 351 */ 352 private void initializeVerifier() { 353 ManifestEntryVerifier mev = null; 354 355 // Verify "META-INF/" entries... 356 try { 357 String[] names = getMetaInfEntryNames(); 358 if (names != null) { 359 for (int i = 0; i < names.length; i++) { 360 JarEntry e = getJarEntry(names[i]); 361 if (e == null) { 362 throw new JarException("corrupted jar file"); 363 } 364 if (!e.isDirectory()) { 365 if (mev == null) { 366 mev = new ManifestEntryVerifier 367 (getManifestFromReference()); 368 } 369 byte[] b = getBytes(e); 370 if (b != null && b.length > 0) { 371 jv.beginEntry(e, mev); 372 jv.update(b.length, b, 0, b.length, mev); 373 jv.update(-1, null, 0, 0, mev); 374 } 375 } 376 } 377 } 378 } catch (IOException ex) { 379 // if we had an error parsing any blocks, just 380 // treat the jar file as being unsigned 381 jv = null; 382 verify = false; 383 if (JarVerifier.debug != null) { 384 JarVerifier.debug.println("jarfile parsing error!"); 385 ex.printStackTrace(); 386 } 387 } 388 389 // if after initializing the verifier we have nothing 390 // signed, we null it out. 391 392 if (jv != null) { 393 394 jv.doneWithMeta(); 395 if (JarVerifier.debug != null) { 396 JarVerifier.debug.println("done with meta!"); 397 } 398 399 if (jv.nothingToVerify()) { 400 if (JarVerifier.debug != null) { 401 JarVerifier.debug.println("nothing to verify!"); 402 } 403 jv = null; 404 verify = false; 405 } 406 } 407 } 408 409 /* 410 * Reads all the bytes for a given entry. Used to process the 411 * META-INF files. 412 */ 413 private byte[] getBytes(ZipEntry ze) throws IOException { 414 try (InputStream is = super.getInputStream(ze)) { 415 return IOUtils.readFully(is, (int)ze.getSize(), true); 416 } 417 } 418 419 /** 420 * Returns an input stream for reading the contents of the specified 421 * zip file entry. 422 * @param ze the zip file entry 423 * @return an input stream for reading the contents of the specified 424 * zip file entry 425 * @throws ZipException if a zip file format error has occurred 426 * @throws IOException if an I/O error has occurred 427 * @throws SecurityException if any of the jar file entries 428 * are incorrectly signed. 429 * @throws IllegalStateException 430 * may be thrown if the jar file has been closed 431 */ 432 public synchronized InputStream getInputStream(ZipEntry ze) 433 throws IOException 434 { 435 maybeInstantiateVerifier(); 436 if (jv == null) { 437 return super.getInputStream(ze); 438 } 439 if (!jvInitialized) { 440 initializeVerifier(); 441 jvInitialized = true; 442 // could be set to null after a call to 443 // initializeVerifier if we have nothing to 444 // verify 445 if (jv == null) 446 return super.getInputStream(ze); 447 } 448 449 // wrap a verifier stream around the real stream 450 return new JarVerifier.VerifierStream( 451 getManifestFromReference(), 452 ze instanceof JarFileEntry ? 453 (JarEntry) ze : getJarEntry(ze.getName()), 454 super.getInputStream(ze), 455 jv); 456 } 457 458 // Statics for hand-coded Boyer-Moore search 459 private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'}; 460 private static final char[] PROFILE_CHARS = { 'p', 'r', 'o', 'f', 'i', 'l', 'e' }; 461 // The bad character shift for "class-path" 462 private static final int[] CLASSPATH_LASTOCC; 463 // The good suffix shift for "class-path" 464 private static final int[] CLASSPATH_OPTOSFT; 465 // The bad character shift for "profile" 466 private static final int[] PROFILE_LASTOCC; 467 // The good suffix shift for "profile" 468 private static final int[] PROFILE_OPTOSFT; 469 470 static { 471 CLASSPATH_LASTOCC = new int[128]; 472 CLASSPATH_OPTOSFT = new int[10]; 473 CLASSPATH_LASTOCC[(int)'c'] = 1; 474 CLASSPATH_LASTOCC[(int)'l'] = 2; 475 CLASSPATH_LASTOCC[(int)'s'] = 5; 476 CLASSPATH_LASTOCC[(int)'-'] = 6; 477 CLASSPATH_LASTOCC[(int)'p'] = 7; 478 CLASSPATH_LASTOCC[(int)'a'] = 8; 479 CLASSPATH_LASTOCC[(int)'t'] = 9; 480 CLASSPATH_LASTOCC[(int)'h'] = 10; 481 for (int i=0; i<9; i++) 482 CLASSPATH_OPTOSFT[i] = 10; 483 CLASSPATH_OPTOSFT[9]=1; 484 485 PROFILE_LASTOCC = new int[128]; 486 PROFILE_OPTOSFT = new int[7]; 487 PROFILE_LASTOCC[(int)'p'] = 1; 488 PROFILE_LASTOCC[(int)'r'] = 2; 489 PROFILE_LASTOCC[(int)'o'] = 3; 490 PROFILE_LASTOCC[(int)'f'] = 4; 491 PROFILE_LASTOCC[(int)'i'] = 5; 492 PROFILE_LASTOCC[(int)'l'] = 6; 493 PROFILE_LASTOCC[(int)'e'] = 7; 494 for (int i=0; i<6; i++) 495 PROFILE_OPTOSFT[i] = 7; 496 PROFILE_OPTOSFT[6] = 1; 497 } 498 499 private JarEntry getManEntry() { 500 if (manEntry == null) { 501 // First look up manifest entry using standard name 502 manEntry = getJarEntry(MANIFEST_NAME); 503 if (manEntry == null) { 504 // If not found, then iterate through all the "META-INF/" 505 // entries to find a match. 506 String[] names = getMetaInfEntryNames(); 507 if (names != null) { 508 for (int i = 0; i < names.length; i++) { 509 if (MANIFEST_NAME.equals( 510 names[i].toUpperCase(Locale.ENGLISH))) { 511 manEntry = getJarEntry(names[i]); 512 break; 513 } 514 } 515 } 516 } 517 } 518 return manEntry; 519 } 520 521 /** 522 * Returns {@code true} iff this JAR file has a manifest with the 523 * Class-Path attribute 524 */ 525 boolean hasClassPathAttribute() throws IOException { 526 checkForSpecialAttributes(); 527 return hasClassPathAttribute; 528 } 529 530 /** 531 * Returns {@code true} iff this JAR file has a manifest with the 532 * Profile attribute 533 */ 534 boolean hasProfileAttribute() throws IOException { 535 checkForSpecialAttributes(); 536 return hasProfileAttribute; 537 } 538 539 /** 540 * Returns true if the pattern {@code src} is found in {@code b}. 541 * The {@code lastOcc} and {@code optoSft} arrays are the precomputed 542 * bad character and good suffix shifts. 543 */ 544 private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) { 545 int len = src.length; 546 int last = b.length - len; 547 int i = 0; 548 next: 549 while (i<=last) { 550 for (int j=(len-1); j>=0; j--) { 551 char c = (char) b[i+j]; 552 c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; 553 if (c != src[j]) { 554 i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); 555 continue next; 556 } 557 } 558 return true; 559 } 560 return false; 561 } 562 563 /** 564 * On first invocation, check if the JAR file has the Class-Path 565 * and/or Profile attributes. A no-op on subsequent calls. 566 */ 567 private void checkForSpecialAttributes() throws IOException { 568 if (hasCheckedSpecialAttributes) return; 569 if (!isKnownNotToHaveSpecialAttributes()) { 570 JarEntry manEntry = getManEntry(); 571 if (manEntry != null) { 572 byte[] b = getBytes(manEntry); 573 if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT)) 574 hasClassPathAttribute = true; 575 if (match(PROFILE_CHARS, b, PROFILE_LASTOCC, PROFILE_OPTOSFT)) 576 hasProfileAttribute = true; 577 } 578 } 579 hasCheckedSpecialAttributes = true; 580 } 581 582 private static String javaHome; 583 private static volatile String[] jarNames; 584 private boolean isKnownNotToHaveSpecialAttributes() { 585 // Optimize away even scanning of manifest for jar files we 586 // deliver which don't have a class-path attribute. If one of 587 // these jars is changed to include such an attribute this code 588 // must be changed. 589 if (javaHome == null) { 590 javaHome = AccessController.doPrivileged( 591 new GetPropertyAction("java.home")); 592 } 593 if (jarNames == null) { 594 String[] names = new String[11]; 595 String fileSep = File.separator; 596 int i = 0; 597 names[i++] = fileSep + "rt.jar"; 598 names[i++] = fileSep + "jsse.jar"; 599 names[i++] = fileSep + "jce.jar"; 600 names[i++] = fileSep + "charsets.jar"; 601 names[i++] = fileSep + "dnsns.jar"; 602 names[i++] = fileSep + "zipfs.jar"; 603 names[i++] = fileSep + "localedata.jar"; 604 names[i++] = fileSep = "cldrdata.jar"; 605 names[i++] = fileSep + "sunjce_provider.jar"; 606 names[i++] = fileSep + "sunpkcs11.jar"; 607 names[i++] = fileSep + "sunec.jar"; 608 jarNames = names; 609 } 610 611 String name = getName(); 612 String localJavaHome = javaHome; 613 if (name.startsWith(localJavaHome)) { 614 String[] names = jarNames; 615 for (int i = 0; i < names.length; i++) { 616 if (name.endsWith(names[i])) { 617 return true; 618 } 619 } 620 } 621 return false; 622 } 623 624 private synchronized void ensureInitialization() { 625 try { 626 maybeInstantiateVerifier(); 627 } catch (IOException e) { 628 throw new RuntimeException(e); 629 } 630 if (jv != null && !jvInitialized) { 631 initializeVerifier(); 632 jvInitialized = true; 633 } 634 } 635 636 JarEntry newEntry(ZipEntry ze) { 637 return new JarFileEntry(ze); 638 } 639 640 Enumeration<String> entryNames(CodeSource[] cs) { 641 ensureInitialization(); 642 if (jv != null) { 643 return jv.entryNames(this, cs); 644 } 645 646 /* 647 * JAR file has no signed content. Is there a non-signing 648 * code source? 649 */ 650 boolean includeUnsigned = false; 651 for (int i = 0; i < cs.length; i++) { 652 if (cs[i].getCodeSigners() == null) { 653 includeUnsigned = true; 654 break; 655 } 656 } 657 if (includeUnsigned) { 658 return unsignedEntryNames(); 659 } else { 660 return new Enumeration<String>() { 661 662 public boolean hasMoreElements() { 663 return false; 664 } 665 666 public String nextElement() { 667 throw new NoSuchElementException(); 668 } 669 }; 670 } 671 } 672 673 /** 674 * Returns an enumeration of the zip file entries 675 * excluding internal JAR mechanism entries and including 676 * signed entries missing from the ZIP directory. 677 */ 678 Enumeration<JarEntry> entries2() { 679 ensureInitialization(); 680 if (jv != null) { 681 return jv.entries2(this, super.entries()); 682 } 683 684 // screen out entries which are never signed 685 final Enumeration<? extends ZipEntry> enum_ = super.entries(); 686 return new Enumeration<JarEntry>() { 687 688 ZipEntry entry; 689 690 public boolean hasMoreElements() { 691 if (entry != null) { 692 return true; 693 } 694 while (enum_.hasMoreElements()) { 695 ZipEntry ze = enum_.nextElement(); 696 if (JarVerifier.isSigningRelated(ze.getName())) { 697 continue; 698 } 699 entry = ze; 700 return true; 701 } 702 return false; 703 } 704 705 public JarFileEntry nextElement() { 706 if (hasMoreElements()) { 707 ZipEntry ze = entry; 708 entry = null; 709 return new JarFileEntry(ze); 710 } 711 throw new NoSuchElementException(); 712 } 713 }; 714 } 715 716 CodeSource[] getCodeSources(URL url) { 717 ensureInitialization(); 718 if (jv != null) { 719 return jv.getCodeSources(this, url); 720 } 721 722 /* 723 * JAR file has no signed content. Is there a non-signing 724 * code source? 725 */ 726 Enumeration<String> unsigned = unsignedEntryNames(); 727 if (unsigned.hasMoreElements()) { 728 return new CodeSource[]{JarVerifier.getUnsignedCS(url)}; 729 } else { 730 return null; 731 } 732 } 733 734 private Enumeration<String> unsignedEntryNames() { 735 final Enumeration<JarEntry> entries = entries(); 736 return new Enumeration<String>() { 737 738 String name; 739 740 /* 741 * Grab entries from ZIP directory but screen out 742 * metadata. 743 */ 744 public boolean hasMoreElements() { 745 if (name != null) { 746 return true; 747 } 748 while (entries.hasMoreElements()) { 749 String value; 750 ZipEntry e = entries.nextElement(); 751 value = e.getName(); 752 if (e.isDirectory() || JarVerifier.isSigningRelated(value)) { 753 continue; 754 } 755 name = value; 756 return true; 757 } 758 return false; 759 } 760 761 public String nextElement() { 762 if (hasMoreElements()) { 763 String value = name; 764 name = null; 765 return value; 766 } 767 throw new NoSuchElementException(); 768 } 769 }; 770 } 771 772 CodeSource getCodeSource(URL url, String name) { 773 ensureInitialization(); 774 if (jv != null) { 775 if (jv.eagerValidation) { 776 CodeSource cs = null; 777 JarEntry je = getJarEntry(name); 778 if (je != null) { 779 cs = jv.getCodeSource(url, this, je); 780 } else { 781 cs = jv.getCodeSource(url, name); 782 } 783 return cs; 784 } else { 785 return jv.getCodeSource(url, name); 786 } 787 } 788 789 return JarVerifier.getUnsignedCS(url); 790 } 791 792 void setEagerValidation(boolean eager) { 793 try { 794 maybeInstantiateVerifier(); 795 } catch (IOException e) { 796 throw new RuntimeException(e); 797 } 798 if (jv != null) { 799 jv.setEagerValidation(eager); 800 } 801 } 802 803 List<Object> getManifestDigests() { 804 ensureInitialization(); 805 if (jv != null) { 806 return jv.getManifestDigests(); 807 } 808 return new ArrayList<Object>(); 809 } 810 }