2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package gov.nasa.jpf.jvm;
21 import gov.nasa.jpf.util.FileUtils;
22 import gov.nasa.jpf.vm.ClassFileMatch;
23 import gov.nasa.jpf.vm.ClassParseException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.net.MalformedURLException;
28 import java.util.jar.JarEntry;
29 import java.util.jar.JarFile;
32 * a ClassFileContainer that loads classes from jar files
34 public class JarClassFileContainer extends JVMClassFileContainer {
35 protected JarFile jar;
36 protected String pathPrefix; // optional
38 static String getContainerUrl (File file){
40 return "jar:" + file.toURI().toURL().toString() + "!/";
41 } catch (MalformedURLException x) {
42 return "jar:" + file.getAbsolutePath() + "!/";
46 public JarClassFileContainer (File file) throws IOException {
47 super(file.getPath(), getContainerUrl(file));
48 jar = new JarFile(file);
51 public JarClassFileContainer (File file, String pathPrefix) throws IOException {
52 super(getPath(file, pathPrefix), getContainerUrl(file));
54 jar = new JarFile(file);
55 this.pathPrefix = getNormalizedPathPrefix(pathPrefix);
59 * make sure the return value ends with '/', and does NOT start with '/'. If
60 * the supplied pathPrefix only contains '/' or an empty string, return null
62 static String getNormalizedPathPrefix(String pathPrefix){
63 if (pathPrefix != null){
64 int len = pathPrefix.length();
66 if (pathPrefix.charAt(0) == '/'){
68 return null; // no need for storing a single '/' prefix
70 pathPrefix = pathPrefix.substring(1); // skip the heading '/'
75 if (pathPrefix.charAt(len-1) != '/'){
82 return null; // empty prefix
85 return null; // null prefix
90 * return our string representation of the complete spec, which is
92 * <jar-pathname>/pathPrefix
94 static String getPath(File file, String pathPrefix){
95 String pn = file.getPath();
97 if (pathPrefix != null){
98 int len = pathPrefix.length();
100 if (pathPrefix.charAt(0) == '/'){
102 return pn; // no need to store a single '/'
116 public ClassFileMatch getMatch(String clsName) throws ClassParseException {
117 String pn = clsName.replace('.', '/') + ".class";
119 if (pathPrefix != null){
120 pn = pathPrefix + pn;
123 JarEntry e = jar.getJarEntry(pn);
126 InputStream is = null;
128 long len = e.getSize();
129 if (len > Integer.MAX_VALUE) {
130 error("classfile too big: " + e.getName());
133 is = jar.getInputStream(e);
135 byte[] data = new byte[(int) len];
136 FileUtils.getContents(is, data);
138 return new JVMClassFileMatch(clsName, getClassURL(clsName), data);
140 } catch (IOException iox) {
141 error("error reading jar entry " + e.getName());
147 } catch (IOException iox) {
148 error("cannot close input stream for file " + e.getName());