Fixing a new bug: Considering parameters with Type and Type array, e.g., T and T[].
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / JarClassFileContainer.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
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
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
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.
17  */
18
19 package gov.nasa.jpf.jvm;
20
21 import gov.nasa.jpf.util.FileUtils;
22 import gov.nasa.jpf.vm.ClassFileMatch;
23 import gov.nasa.jpf.vm.ClassParseException;
24 import java.io.File;
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;
30
31 /**
32  * a ClassFileContainer that loads classes from jar files
33  */
34 public class JarClassFileContainer extends JVMClassFileContainer {
35   protected JarFile jar;
36   protected String pathPrefix; // optional
37
38   static String getContainerUrl (File file){
39     try {
40       return "jar:" + file.toURI().toURL().toString() + "!/";
41     } catch (MalformedURLException x) {
42       return "jar:" + file.getAbsolutePath() + "!/";
43     }
44   }
45
46   public JarClassFileContainer (File file) throws IOException {
47     super(file.getPath(), getContainerUrl(file));
48     jar = new JarFile(file);
49   }
50
51   public JarClassFileContainer (File file, String pathPrefix) throws IOException {
52     super(getPath(file, pathPrefix), getContainerUrl(file));
53
54     jar = new JarFile(file);
55     this.pathPrefix = getNormalizedPathPrefix(pathPrefix);
56   }
57   
58   /**
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
61    */
62   static String getNormalizedPathPrefix(String pathPrefix){
63     if (pathPrefix != null){
64       int len = pathPrefix.length();
65       if (len > 0){
66         if (pathPrefix.charAt(0) == '/'){
67           if (len == 1){
68             return null; // no need for storing a single '/' prefix
69           } else {
70             pathPrefix = pathPrefix.substring(1); // skip the heading '/'
71             len--;
72           }
73         }
74         
75         if (pathPrefix.charAt(len-1) != '/'){
76           pathPrefix += '/';
77         }
78         
79         return pathPrefix;
80         
81       } else {
82         return null; // empty prefix
83       }
84     } else {
85       return null; // null prefix
86     }
87   }
88
89   /**
90    * return our string representation of the complete spec, which is
91    * 
92    *   <jar-pathname>/pathPrefix
93    */
94   static String getPath(File file, String pathPrefix){
95     String pn = file.getPath();
96    
97     if (pathPrefix != null){
98       int len = pathPrefix.length();
99       if (len > 0){
100         if (pathPrefix.charAt(0) == '/'){
101           if (len == 1){
102             return pn; // no need to store a single '/'
103           }
104         } else {
105           pn += '/';
106         }
107         
108         pn += pathPrefix;
109       }
110     }
111     
112     return pn;
113   }
114     
115   @Override
116   public ClassFileMatch getMatch(String clsName) throws ClassParseException {
117     String pn = clsName.replace('.', '/') + ".class";
118     
119     if (pathPrefix != null){
120       pn = pathPrefix + pn;
121     }
122     
123     JarEntry e = jar.getJarEntry(pn);
124
125     if (e != null) {
126       InputStream is = null;
127       try {
128         long len = e.getSize();
129         if (len > Integer.MAX_VALUE) {
130           error("classfile too big: " + e.getName());
131         }
132
133         is = jar.getInputStream(e);
134
135         byte[] data = new byte[(int) len];
136         FileUtils.getContents(is, data);
137
138         return new JVMClassFileMatch(clsName, getClassURL(clsName), data);
139
140       } catch (IOException iox) {
141         error("error reading jar entry " + e.getName());
142
143       } finally {
144         if (is != null) {
145           try {
146             is.close();
147           } catch (IOException iox) {
148             error("cannot close input stream for file " + e.getName());
149           }
150         }
151       }
152     }
153
154     return null;
155   }
156
157 }