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.CodeSource;
38 import jdk.internal.misc.SharedSecrets;
39 import sun.security.action.GetPropertyAction;
40 import sun.security.util.ManifestEntryVerifier;
41 import sun.security.util.SignatureFileVerifier;
42
43 /**
44 * The {@code JarFile} class is used to read the contents of a jar file
45 * from any file that can be opened with {@code java.io.RandomAccessFile}.
46 * It extends the class {@code java.util.zip.ZipFile} with support
47 * for reading an optional {@code Manifest} entry, and support for
48 * processing multi-release jar files. The {@code Manifest} can be used
49 * to specify meta-information about the jar file and its entries.
50 *
51 * <p><a name="multirelease">A multi-release jar file</a> is a jar file that
52 * contains a manifest with a main attribute named "Multi-Release",
53 * a set of "base" entries, some of which are public classes with public
54 * or protected methods that comprise the public interface of the jar file,
55 * and a set of "versioned" entries contained in subdirectories of the
56 * "META-INF/versions" directory. The versioned entries are partitioned by the
57 * major version of the Java platform. A versioned entry, with a version
58 * {@code n}, {@code 8 < n}, in the "META-INF/versions/{n}" directory overrides
810 // wrap a verifier stream around the real stream
811 return new JarVerifier.VerifierStream(
812 getManifestFromReference(),
813 verifiableEntry(ze),
814 super.getInputStream(ze),
815 jv);
816 }
817
818 private JarEntry verifiableEntry(ZipEntry ze) {
819 if (ze instanceof JarFileEntry) {
820 // assure the name and entry match for verification
821 return ((JarFileEntry)ze).realEntry();
822 }
823 ze = getJarEntry(ze.getName());
824 if (ze instanceof JarFileEntry) {
825 return ((JarFileEntry)ze).realEntry();
826 }
827 return (JarEntry)ze;
828 }
829
830 // Statics for hand-coded Boyer-Moore search
831 private static final byte[] CLASSPATH_CHARS =
832 {'C','L','A','S','S','-','P','A','T','H', ':', ' '};
833
834 // The bad character shift for "class-path: "
835 private static final byte[] CLASSPATH_LASTOCC;
836
837 // The good suffix shift for "class-path: "
838 private static final byte[] CLASSPATH_OPTOSFT;
839
840 private static final byte[] MULTIRELEASE_CHARS =
841 {'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':',
842 ' ', 'T', 'R', 'U', 'E'};
843
844 // The bad character shift for "multi-release: true"
845 private static final byte[] MULTIRELEASE_LASTOCC;
846
847 // The good suffix shift for "multi-release: true"
848 private static final byte[] MULTIRELEASE_OPTOSFT;
849
850 static {
851 CLASSPATH_LASTOCC = new byte[64];
852 CLASSPATH_OPTOSFT = new byte[12];
853 CLASSPATH_LASTOCC[(int)'C' - 32] = 1;
854 CLASSPATH_LASTOCC[(int)'L' - 32] = 2;
855 CLASSPATH_LASTOCC[(int)'S' - 32] = 5;
856 CLASSPATH_LASTOCC[(int)'-' - 32] = 6;
857 CLASSPATH_LASTOCC[(int)'P' - 32] = 7;
858 CLASSPATH_LASTOCC[(int)'A' - 32] = 8;
859 CLASSPATH_LASTOCC[(int)'T' - 32] = 9;
860 CLASSPATH_LASTOCC[(int)'H' - 32] = 10;
861 CLASSPATH_LASTOCC[(int)':' - 32] = 11;
862 CLASSPATH_LASTOCC[(int)' ' - 32] = 12;
863 for (int i = 0; i < 11; i++) {
864 CLASSPATH_OPTOSFT[i] = 12;
865 }
866 CLASSPATH_OPTOSFT[11] = 1;
867
868 MULTIRELEASE_LASTOCC = new byte[64];
869 MULTIRELEASE_OPTOSFT = new byte[19];
870 MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1;
871 MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5;
872 MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6;
873 MULTIRELEASE_LASTOCC[(int)'L' - 32] = 9;
874 MULTIRELEASE_LASTOCC[(int)'A' - 32] = 11;
875 MULTIRELEASE_LASTOCC[(int)'S' - 32] = 12;
876 MULTIRELEASE_LASTOCC[(int)':' - 32] = 14;
877 MULTIRELEASE_LASTOCC[(int)' ' - 32] = 15;
878 MULTIRELEASE_LASTOCC[(int)'T' - 32] = 16;
879 MULTIRELEASE_LASTOCC[(int)'R' - 32] = 17;
880 MULTIRELEASE_LASTOCC[(int)'U' - 32] = 18;
881 MULTIRELEASE_LASTOCC[(int)'E' - 32] = 19;
882 for (int i = 0; i < 17; i++) {
883 MULTIRELEASE_OPTOSFT[i] = 19;
884 }
885 MULTIRELEASE_OPTOSFT[17] = 6;
886 MULTIRELEASE_OPTOSFT[18] = 1;
887 }
888
889 private JarEntry getManEntry() {
890 if (manEntry == null) {
891 // First look up manifest entry using standard name
892 ZipEntry manEntry = super.getEntry(MANIFEST_NAME);
893 if (manEntry == null) {
894 // If not found, then iterate through all the "META-INF/"
895 // entries to find a match.
896 String[] names = getMetaInfEntryNames();
897 if (names != null) {
898 for (String name : names) {
899 if (MANIFEST_NAME.equals(name.toUpperCase(Locale.ENGLISH))) {
900 manEntry = super.getEntry(name);
901 break;
902 }
903 }
904 }
905 }
906 this.manEntry = (manEntry == null)
907 ? null
908 : new JarFileEntry(manEntry.getName(), manEntry);
909 }
910 return manEntry;
911 }
912
913 /**
914 * Returns {@code true} iff this JAR file has a manifest with the
915 * Class-Path attribute
916 */
917 boolean hasClassPathAttribute() throws IOException {
918 checkForSpecialAttributes();
919 return hasClassPathAttribute;
920 }
921
922 /**
923 * Returns true if the pattern {@code src} is found in {@code b}.
924 * The {@code lastOcc} array is the precomputed bad character shifts.
925 * Since there are no repeated substring in our search strings,
926 * the good suffix shifts can be replaced with a comparison.
927 */
928 private int match(byte[] src, byte[] b, byte[] lastOcc, byte[] optoSft) {
929 int len = src.length;
930 int last = b.length - len;
931 int i = 0;
932 next:
933 while (i <= last) {
934 for (int j = (len - 1); j >= 0; j--) {
935 byte c = b[i + j];
936 if (c >= ' ' && c <= 'z') {
937 if (c >= 'a') c -= 32; // Canonicalize
938
939 if (c != src[j]) {
940 // no match
941 int badShift = lastOcc[c - 32];
942 i += Math.max(j + 1 - badShift, optoSft[j]);
943 continue next;
944 }
945 } else {
946 // no match, character not valid for name
947 i += len;
948 continue next;
949 }
950 }
951 return i;
952 }
953 return -1;
954 }
955
956 /**
957 * On first invocation, check if the JAR file has the Class-Path
958 * and the Multi-Release attribute. A no-op on subsequent calls.
959 */
960 private void checkForSpecialAttributes() throws IOException {
961 if (hasCheckedSpecialAttributes) {
962 return;
963 }
964 synchronized (this) {
965 if (hasCheckedSpecialAttributes) {
966 return;
967 }
968 JarEntry manEntry = getManEntry();
969 if (manEntry != null) {
970 byte[] b = getBytes(manEntry);
971 hasClassPathAttribute = match(CLASSPATH_CHARS, b,
972 CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT) != -1;
973 // is this a multi-release jar file
974 if (MULTI_RELEASE_ENABLED) {
975 int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC,
976 MULTIRELEASE_OPTOSFT);
977 if (i != -1) {
978 i += MULTIRELEASE_CHARS.length;
979 if (i < b.length) {
980 byte c = b[i++];
981 // Check that the value is followed by a newline
982 // and does not have a continuation
983 if (c == '\n' &&
984 (i == b.length || b[i] != ' ')) {
985 isMultiRelease = true;
986 } else if (c == '\r') {
987 if (i == b.length) {
988 isMultiRelease = true;
989 } else {
990 c = b[i++];
991 if (c == '\n') {
992 if (i == b.length || b[i] != ' ') {
993 isMultiRelease = true;
994 }
995 } else if (c != ' ') {
996 isMultiRelease = true;
997 }
998 }
999 }
1000 }
1001 }
1002 }
1003 }
1004 hasCheckedSpecialAttributes = true;
1005 }
1006 }
1007
1008 private synchronized void ensureInitialization() {
1009 try {
1010 maybeInstantiateVerifier();
1011 } catch (IOException e) {
1012 throw new RuntimeException(e);
1013 }
1014 if (jv != null && !jvInitialized) {
1015 initializeVerifier();
1016 jvInitialized = true;
1017 }
1018 }
1019
1020 JarEntry newEntry(ZipEntry ze) {
1021 return new JarFileEntry(ze);
|
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.CodeSource;
38 import jdk.internal.misc.SharedSecrets;
39 import jdk.internal.util.jar.JarAttributes;
40 import sun.security.action.GetPropertyAction;
41 import sun.security.util.ManifestEntryVerifier;
42 import sun.security.util.SignatureFileVerifier;
43
44 /**
45 * The {@code JarFile} class is used to read the contents of a jar file
46 * from any file that can be opened with {@code java.io.RandomAccessFile}.
47 * It extends the class {@code java.util.zip.ZipFile} with support
48 * for reading an optional {@code Manifest} entry, and support for
49 * processing multi-release jar files. The {@code Manifest} can be used
50 * to specify meta-information about the jar file and its entries.
51 *
52 * <p><a name="multirelease">A multi-release jar file</a> is a jar file that
53 * contains a manifest with a main attribute named "Multi-Release",
54 * a set of "base" entries, some of which are public classes with public
55 * or protected methods that comprise the public interface of the jar file,
56 * and a set of "versioned" entries contained in subdirectories of the
57 * "META-INF/versions" directory. The versioned entries are partitioned by the
58 * major version of the Java platform. A versioned entry, with a version
59 * {@code n}, {@code 8 < n}, in the "META-INF/versions/{n}" directory overrides
811 // wrap a verifier stream around the real stream
812 return new JarVerifier.VerifierStream(
813 getManifestFromReference(),
814 verifiableEntry(ze),
815 super.getInputStream(ze),
816 jv);
817 }
818
819 private JarEntry verifiableEntry(ZipEntry ze) {
820 if (ze instanceof JarFileEntry) {
821 // assure the name and entry match for verification
822 return ((JarFileEntry)ze).realEntry();
823 }
824 ze = getJarEntry(ze.getName());
825 if (ze instanceof JarFileEntry) {
826 return ((JarFileEntry)ze).realEntry();
827 }
828 return (JarEntry)ze;
829 }
830
831 private JarEntry getManEntry() {
832 if (manEntry == null) {
833 // First look up manifest entry using standard name
834 ZipEntry manEntry = super.getEntry(MANIFEST_NAME);
835 if (manEntry == null) {
836 // If not found, then iterate through all the "META-INF/"
837 // entries to find a match.
838 String[] names = getMetaInfEntryNames();
839 if (names != null) {
840 for (String name : names) {
841 if (MANIFEST_NAME.equals(name.toUpperCase(Locale.ENGLISH))) {
842 manEntry = super.getEntry(name);
843 break;
844 }
845 }
846 }
847 }
848 this.manEntry = (manEntry == null)
849 ? null
850 : new JarFileEntry(manEntry.getName(), manEntry);
851 }
852 return manEntry;
853 }
854
855 /**
856 * Returns {@code true} iff this JAR file has a manifest with the
857 * Class-Path attribute
858 */
859 boolean hasClassPathAttribute() throws IOException {
860 checkForSpecialAttributes();
861 return hasClassPathAttribute;
862 }
863
864
865 /**
866 * On first invocation, check if the JAR file has the Class-Path
867 * and the Multi-Release attribute. A no-op on subsequent calls.
868 */
869 private void checkForSpecialAttributes() throws IOException {
870 if (hasCheckedSpecialAttributes) {
871 return;
872 }
873 synchronized (this) {
874 if (hasCheckedSpecialAttributes) {
875 return;
876 }
877 JarEntry manEntry = getManEntry();
878 if (manEntry != null) {
879 byte[] b = getBytes(manEntry);
880 hasClassPathAttribute = JarAttributes.hasClassPathAttribute(b);
881 // is this a multi-release jar file
882 if (MULTI_RELEASE_ENABLED) {
883 isMultiRelease = JarAttributes.isMultiRelease(b);
884 }
885 }
886 hasCheckedSpecialAttributes = true;
887 }
888 }
889
890 private synchronized void ensureInitialization() {
891 try {
892 maybeInstantiateVerifier();
893 } catch (IOException e) {
894 throw new RuntimeException(e);
895 }
896 if (jv != null && !jvInitialized) {
897 initializeVerifier();
898 jvInitialized = true;
899 }
900 }
901
902 JarEntry newEntry(ZipEntry ze) {
903 return new JarFileEntry(ze);
|