61 private SoftReference<Manifest> manRef; |
61 private SoftReference<Manifest> manRef; |
62 private JarEntry manEntry; |
62 private JarEntry manEntry; |
63 private JarVerifier jv; |
63 private JarVerifier jv; |
64 private boolean jvInitialized; |
64 private boolean jvInitialized; |
65 private boolean verify; |
65 private boolean verify; |
66 private boolean computedHasClassPathAttribute; |
66 |
|
67 // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true) |
67 private boolean hasClassPathAttribute; |
68 private boolean hasClassPathAttribute; |
|
69 // indicates if Profile attribute present (only valid if hasCheckedSpecialAttributes true) |
|
70 private boolean hasProfileAttribute; |
|
71 // true if manifest checked for special attributes |
|
72 private volatile boolean hasCheckedSpecialAttributes; |
68 |
73 |
69 // Set up JavaUtilJarAccess in SharedSecrets |
74 // Set up JavaUtilJarAccess in SharedSecrets |
70 static { |
75 static { |
71 SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); |
76 SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl()); |
72 } |
77 } |
419 (JarEntry) ze : getJarEntry(ze.getName()), |
424 (JarEntry) ze : getJarEntry(ze.getName()), |
420 super.getInputStream(ze), |
425 super.getInputStream(ze), |
421 jv); |
426 jv); |
422 } |
427 } |
423 |
428 |
424 // Statics for hand-coded Boyer-Moore search in hasClassPathAttribute() |
429 // Statics for hand-coded Boyer-Moore search |
|
430 private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'}; |
|
431 private static final char[] PROFILE_CHARS = { 'p', 'r', 'o', 'f', 'i', 'l', 'e' }; |
425 // The bad character shift for "class-path" |
432 // The bad character shift for "class-path" |
426 private static int[] lastOcc; |
433 private static final int[] CLASSPATH_LASTOCC; |
427 // The good suffix shift for "class-path" |
434 // The good suffix shift for "class-path" |
428 private static int[] optoSft; |
435 private static final int[] CLASSPATH_OPTOSFT; |
429 // Initialize the shift arrays to search for "class-path" |
436 // The bad character shift for "profile" |
430 private static char[] src = {'c','l','a','s','s','-','p','a','t','h'}; |
437 private static final int[] PROFILE_LASTOCC; |
|
438 // The good suffix shift for "profile" |
|
439 private static final int[] PROFILE_OPTOSFT; |
|
440 |
431 static { |
441 static { |
432 lastOcc = new int[128]; |
442 CLASSPATH_LASTOCC = new int[128]; |
433 optoSft = new int[10]; |
443 CLASSPATH_OPTOSFT = new int[10]; |
434 lastOcc[(int)'c']=1; |
444 CLASSPATH_LASTOCC[(int)'c'] = 1; |
435 lastOcc[(int)'l']=2; |
445 CLASSPATH_LASTOCC[(int)'l'] = 2; |
436 lastOcc[(int)'s']=5; |
446 CLASSPATH_LASTOCC[(int)'s'] = 5; |
437 lastOcc[(int)'-']=6; |
447 CLASSPATH_LASTOCC[(int)'-'] = 6; |
438 lastOcc[(int)'p']=7; |
448 CLASSPATH_LASTOCC[(int)'p'] = 7; |
439 lastOcc[(int)'a']=8; |
449 CLASSPATH_LASTOCC[(int)'a'] = 8; |
440 lastOcc[(int)'t']=9; |
450 CLASSPATH_LASTOCC[(int)'t'] = 9; |
441 lastOcc[(int)'h']=10; |
451 CLASSPATH_LASTOCC[(int)'h'] = 10; |
442 for (int i=0; i<9; i++) |
452 for (int i=0; i<9; i++) |
443 optoSft[i]=10; |
453 CLASSPATH_OPTOSFT[i] = 10; |
444 optoSft[9]=1; |
454 CLASSPATH_OPTOSFT[9]=1; |
|
455 |
|
456 PROFILE_LASTOCC = new int[128]; |
|
457 PROFILE_OPTOSFT = new int[7]; |
|
458 PROFILE_LASTOCC[(int)'p'] = 1; |
|
459 PROFILE_LASTOCC[(int)'r'] = 2; |
|
460 PROFILE_LASTOCC[(int)'o'] = 3; |
|
461 PROFILE_LASTOCC[(int)'f'] = 4; |
|
462 PROFILE_LASTOCC[(int)'i'] = 5; |
|
463 PROFILE_LASTOCC[(int)'l'] = 6; |
|
464 PROFILE_LASTOCC[(int)'e'] = 7; |
|
465 for (int i=0; i<6; i++) |
|
466 PROFILE_OPTOSFT[i] = 7; |
|
467 PROFILE_OPTOSFT[6] = 1; |
445 } |
468 } |
446 |
469 |
447 private JarEntry getManEntry() { |
470 private JarEntry getManEntry() { |
448 if (manEntry == null) { |
471 if (manEntry == null) { |
449 // First look up manifest entry using standard name |
472 // First look up manifest entry using standard name |
464 } |
487 } |
465 } |
488 } |
466 return manEntry; |
489 return manEntry; |
467 } |
490 } |
468 |
491 |
469 // Returns true iff this jar file has a manifest with a class path |
492 /** |
470 // attribute. Returns false if there is no manifest or the manifest |
493 * Returns {@code true} iff this JAR file has a manifest with the |
471 // does not contain a "Class-Path" attribute. Currently exported to |
494 * Class-Path attribute |
472 // core libraries via sun.misc.SharedSecrets. |
495 */ |
473 boolean hasClassPathAttribute() throws IOException { |
496 boolean hasClassPathAttribute() throws IOException { |
474 if (computedHasClassPathAttribute) { |
497 checkForSpecialAttributes(); |
475 return hasClassPathAttribute; |
498 return hasClassPathAttribute; |
476 } |
499 } |
477 |
500 |
478 hasClassPathAttribute = false; |
501 /** |
479 if (!isKnownToNotHaveClassPathAttribute()) { |
502 * Returns {@code true} iff this JAR file has a manifest with the |
|
503 * Profile attribute |
|
504 */ |
|
505 boolean hasProfileAttribute() throws IOException { |
|
506 checkForSpecialAttributes(); |
|
507 return hasProfileAttribute; |
|
508 } |
|
509 |
|
510 /** |
|
511 * Returns true if the pattern {@code src} is found in {@code b}. |
|
512 * The {@code lastOcc} and {@code optoSft} arrays are the precomputed |
|
513 * bad character and good suffix shifts. |
|
514 */ |
|
515 private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) { |
|
516 int len = src.length; |
|
517 int last = b.length - len; |
|
518 int i = 0; |
|
519 next: |
|
520 while (i<=last) { |
|
521 for (int j=(len-1); j>=0; j--) { |
|
522 char c = (char) b[i+j]; |
|
523 c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; |
|
524 if (c != src[j]) { |
|
525 i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); |
|
526 continue next; |
|
527 } |
|
528 } |
|
529 return true; |
|
530 } |
|
531 return false; |
|
532 } |
|
533 |
|
534 /** |
|
535 * On first invocation, check if the JAR file has the Class-Path |
|
536 * and/or Profile attributes. A no-op on subsequent calls. |
|
537 */ |
|
538 private void checkForSpecialAttributes() throws IOException { |
|
539 if (hasCheckedSpecialAttributes) return; |
|
540 if (!isKnownNotToHaveSpecialAttributes()) { |
480 JarEntry manEntry = getManEntry(); |
541 JarEntry manEntry = getManEntry(); |
481 if (manEntry != null) { |
542 if (manEntry != null) { |
482 byte[] b = new byte[(int)manEntry.getSize()]; |
543 byte[] b = new byte[(int)manEntry.getSize()]; |
483 try (DataInputStream dis = new DataInputStream( |
544 try (DataInputStream dis = new DataInputStream( |
484 super.getInputStream(manEntry))) { |
545 super.getInputStream(manEntry))) { |
485 dis.readFully(b, 0, b.length); |
546 dis.readFully(b, 0, b.length); |
486 } |
547 } |
487 |
548 if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT)) |
488 int last = b.length - src.length; |
|
489 int i = 0; |
|
490 next: |
|
491 while (i<=last) { |
|
492 for (int j=9; j>=0; j--) { |
|
493 char c = (char) b[i+j]; |
|
494 c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c; |
|
495 if (c != src[j]) { |
|
496 i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]); |
|
497 continue next; |
|
498 } |
|
499 } |
|
500 hasClassPathAttribute = true; |
549 hasClassPathAttribute = true; |
501 break; |
550 if (match(PROFILE_CHARS, b, PROFILE_LASTOCC, PROFILE_OPTOSFT)) |
502 } |
551 hasProfileAttribute = true; |
503 } |
552 } |
504 } |
553 } |
505 computedHasClassPathAttribute = true; |
554 hasCheckedSpecialAttributes = true; |
506 return hasClassPathAttribute; |
|
507 } |
555 } |
508 |
556 |
509 private static String javaHome; |
557 private static String javaHome; |
510 private static String[] jarNames; |
558 private static volatile String[] jarNames; |
511 private boolean isKnownToNotHaveClassPathAttribute() { |
559 private boolean isKnownNotToHaveSpecialAttributes() { |
512 // Optimize away even scanning of manifest for jar files we |
560 // Optimize away even scanning of manifest for jar files we |
513 // deliver which don't have a class-path attribute. If one of |
561 // deliver which don't have a class-path attribute. If one of |
514 // these jars is changed to include such an attribute this code |
562 // these jars is changed to include such an attribute this code |
515 // must be changed. |
563 // must be changed. |
516 if (javaHome == null) { |
564 if (javaHome == null) { |
517 javaHome = AccessController.doPrivileged( |
565 javaHome = AccessController.doPrivileged( |
518 new GetPropertyAction("java.home")); |
566 new GetPropertyAction("java.home")); |
519 } |
567 } |
520 if (jarNames == null) { |
568 if (jarNames == null) { |
521 String[] names = new String[10]; |
569 String[] names = new String[11]; |
522 String fileSep = File.separator; |
570 String fileSep = File.separator; |
523 int i = 0; |
571 int i = 0; |
524 names[i++] = fileSep + "rt.jar"; |
572 names[i++] = fileSep + "rt.jar"; |
525 names[i++] = fileSep + "sunrsasign.jar"; |
|
526 names[i++] = fileSep + "jsse.jar"; |
573 names[i++] = fileSep + "jsse.jar"; |
527 names[i++] = fileSep + "jce.jar"; |
574 names[i++] = fileSep + "jce.jar"; |
528 names[i++] = fileSep + "charsets.jar"; |
575 names[i++] = fileSep + "charsets.jar"; |
529 names[i++] = fileSep + "dnsns.jar"; |
576 names[i++] = fileSep + "dnsns.jar"; |
530 names[i++] = fileSep + "ldapsec.jar"; |
577 names[i++] = fileSep + "zipfs.jar"; |
531 names[i++] = fileSep + "localedata.jar"; |
578 names[i++] = fileSep + "localedata.jar"; |
|
579 names[i++] = fileSep = "cldrdata.jar"; |
532 names[i++] = fileSep + "sunjce_provider.jar"; |
580 names[i++] = fileSep + "sunjce_provider.jar"; |
533 names[i++] = fileSep + "sunpkcs11.jar"; |
581 names[i++] = fileSep + "sunpkcs11.jar"; |
|
582 names[i++] = fileSep + "sunec.jar"; |
534 jarNames = names; |
583 jarNames = names; |
535 } |
584 } |
536 |
585 |
537 String name = getName(); |
586 String name = getName(); |
538 String localJavaHome = javaHome; |
587 String localJavaHome = javaHome; |