Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/util/Source.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
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 package gov.nasa.jpf.util; | |
19 | |
20 | |
21 import gov.nasa.jpf.Config; | |
22 import gov.nasa.jpf.JPF; | |
23 | |
24 import java.io.BufferedReader; | |
25 import java.io.File; | |
26 import java.io.FileInputStream; | |
27 import java.io.FileNotFoundException; | |
28 import java.io.IOException; | |
29 import java.io.InputStream; | |
30 import java.io.InputStreamReader; | |
31 import java.util.ArrayList; | |
32 import java.util.Hashtable; | |
33 import java.util.LinkedList; | |
34 import java.util.List; | |
35 import java.util.jar.JarEntry; | |
36 import java.util.jar.JarFile; | |
37 import java.util.logging.Logger; | |
38 | |
39 | |
40 /** | |
41 * utility class to access arbitrary source files by line number | |
42 * sources can be files inside of root directories, or | |
43 * can be entries in jars | |
44 */ | |
45 public class Source { | |
46 | |
47 static Logger logger = JPF.getLogger("gov.nasa.jpf.util.Source"); | |
48 | |
49 static List<SourceRoot> sourceRoots; | |
50 static Hashtable<String,Source> sources = new Hashtable<String,Source>(); | |
51 static Source noSource = new Source(null, null); | |
52 | |
53 static abstract class SourceRoot { // common base | |
54 abstract InputStream getInputStream (String fname); | |
55 } | |
56 | |
57 static class DirRoot extends SourceRoot { | |
58 String path; | |
59 | |
60 DirRoot (String path){ | |
61 this.path = path; | |
62 } | |
63 | |
64 @Override | |
65 InputStream getInputStream (String fname) { | |
66 if (File.separatorChar != '/'){ | |
67 fname = fname.replace('/', File.separatorChar); | |
68 } | |
69 | |
70 File f = new File(path, fname); | |
71 if (f.exists()) { | |
72 try { | |
73 return new FileInputStream(f); | |
74 } catch (FileNotFoundException fnfx) { | |
75 return null; | |
76 } | |
77 } else { | |
78 return null; | |
79 } | |
80 } | |
81 | |
82 @Override | |
83 public boolean equals (Object other){ | |
84 return (other != null) && (other instanceof DirRoot) && | |
85 path.equals(((DirRoot)other).path); | |
86 } | |
87 | |
88 @Override | |
89 public String toString() { | |
90 return path; | |
91 } | |
92 } | |
93 | |
94 static class JarRoot extends SourceRoot { | |
95 JarFile jar; | |
96 String entryPrefix; | |
97 | |
98 JarRoot (String path, String ep) throws IOException { | |
99 jar = new JarFile(path); | |
100 | |
101 if (ep == null) { | |
102 entryPrefix = null; | |
103 } else { | |
104 entryPrefix = ep; | |
105 if (ep.charAt(ep.length()-1) != '/') { | |
106 entryPrefix += '/'; | |
107 } | |
108 } | |
109 } | |
110 | |
111 @Override | |
112 InputStream getInputStream (String fname) { | |
113 String en = (entryPrefix != null) ? entryPrefix + fname : fname; | |
114 JarEntry entry = jar.getJarEntry(en); | |
115 if (entry != null) { | |
116 try { | |
117 return jar.getInputStream(entry); | |
118 } catch (IOException e) { | |
119 return null; | |
120 } | |
121 } else { | |
122 return null; | |
123 } | |
124 } | |
125 | |
126 @Override | |
127 public boolean equals (Object other){ | |
128 if ( (other != null) && (other instanceof JarRoot)){ | |
129 | |
130 // just how hard can it be to check if two JarFiles instances refer to | |
131 // the same file? | |
132 JarRoot o = (JarRoot)other; | |
133 File f = new File(jar.getName()); | |
134 File fOther = new File(o.jar.getName()); | |
135 if (f.getAbsolutePath().equals(fOther.getAbsolutePath())){ | |
136 if (entryPrefix == null){ | |
137 return o.entryPrefix == null; | |
138 } else { | |
139 entryPrefix.equals(o.entryPrefix); | |
140 } | |
141 } | |
142 } | |
143 | |
144 return false; | |
145 } | |
146 | |
147 @Override | |
148 public String toString() { | |
149 return jar.getName(); | |
150 } | |
151 } | |
152 | |
153 static void addSourceRoot (Config config, List<SourceRoot> roots, String spec){ | |
154 SourceRoot sr = null; | |
155 | |
156 try { | |
157 int i = spec.indexOf(".jar"); | |
158 if (i >= 0) { // jar | |
159 String pn = FileUtils.asPlatformPath(spec.substring(0, i + 4)); | |
160 File jar = new File(pn); | |
161 if (jar.exists()) { | |
162 int i0 = i + 5; // scrub the leading path separator | |
163 // JarFile assumes Unix for archive-internal paths (also on Windows) | |
164 String ep = (spec.length() > i0) ? FileUtils.asCanonicalUnixPath(spec.substring(i0)) : null; | |
165 // we should probably check here if there is such a dir in the Jar | |
166 sr = new JarRoot(pn, ep); | |
167 } | |
168 | |
169 } else { // directory | |
170 String pn = FileUtils.asPlatformPath(spec); | |
171 File dir = new File(pn); | |
172 if (dir.exists()) { | |
173 sr = new DirRoot(pn); | |
174 } | |
175 } | |
176 } catch (IOException iox) { | |
177 // we report this below | |
178 } | |
179 | |
180 if (sr != null) { | |
181 if (!roots.contains(sr)){ | |
182 roots.add(sr); | |
183 } | |
184 } else { | |
185 logger.info("not a valid source root: " + spec); | |
186 } | |
187 } | |
188 | |
189 static String findSrcRoot (String cpEntry){ | |
190 if (cpEntry.endsWith(".jar")){ | |
191 // check if there is a 'src' dir in the jar | |
192 try { | |
193 JarFile jf = new JarFile(cpEntry); | |
194 JarEntry srcEntry = jf.getJarEntry("src"); | |
195 if (srcEntry != null && srcEntry.isDirectory()) { | |
196 return jf.getName() + "/src"; // jar internal paths use '/' separators | |
197 } | |
198 } catch (IOException iox){ | |
199 return null; | |
200 } | |
201 | |
202 } else { // is it a dir? | |
203 File cpe = new File(cpEntry); | |
204 if (cpe.isDirectory()){ | |
205 // go up until you hit a dir that has a 'src' subdir | |
206 // remember the traversed path elements | |
207 LinkedList<String> dirStack = new LinkedList<String>(); | |
208 dirStack.addFirst(cpe.getName()); | |
209 for (File pd = cpe.getParentFile(); pd != null; pd = pd.getParentFile()){ | |
210 File sd = new File(pd,"src"); | |
211 if (sd.isDirectory()){ | |
212 String srcRoot = sd.getPath(); | |
213 for (String e : dirStack) { | |
214 srcRoot = srcRoot + File.separatorChar + e; | |
215 } | |
216 sd = new File(srcRoot); | |
217 if (sd.isDirectory()){ | |
218 return srcRoot; | |
219 } | |
220 } else { | |
221 dirStack.addFirst(pd.getName()); | |
222 } | |
223 } | |
224 } | |
225 } | |
226 | |
227 return null; | |
228 } | |
229 | |
230 public static void init (Config config) { | |
231 ArrayList<SourceRoot> roots = new ArrayList<SourceRoot>(); | |
232 | |
233 String[] srcPaths = config.getCompactStringArray("sourcepath"); | |
234 if (srcPaths != null){ | |
235 for (String e : srcPaths){ | |
236 addSourceRoot(config, roots, e); | |
237 } | |
238 } | |
239 | |
240 sourceRoots = roots; | |
241 sources.clear(); | |
242 | |
243 //printRoots(); | |
244 } | |
245 | |
246 // for debugging purposes | |
247 static void printRoots() { | |
248 System.out.println("source roots:"); | |
249 for (SourceRoot sr : sourceRoots){ | |
250 System.out.println(" " + sr); | |
251 } | |
252 } | |
253 | |
254 public static Source getSource (String relPathName) { | |
255 if (relPathName == null){ | |
256 return null; | |
257 } | |
258 | |
259 Source s = sources.get(relPathName); | |
260 if (s == noSource) { | |
261 return null; | |
262 } | |
263 | |
264 if (s == null) { | |
265 for (SourceRoot root : sourceRoots) { | |
266 InputStream is = root.getInputStream(relPathName); | |
267 if (is != null) { | |
268 try { | |
269 s = new Source(root,relPathName); | |
270 s.loadLines(is); | |
271 is.close(); | |
272 | |
273 sources.put(relPathName, s); | |
274 return s; | |
275 } catch (IOException iox) { | |
276 logger.warning("error reading " + relPathName + " from" + root); | |
277 return null; | |
278 } | |
279 } | |
280 } | |
281 } else { | |
282 return s; | |
283 } | |
284 | |
285 sources.put(relPathName, noSource); | |
286 return null; | |
287 } | |
288 | |
289 //--- the Source instance data itself | |
290 protected SourceRoot root; | |
291 protected String fname; | |
292 protected String[] lines; | |
293 | |
294 | |
295 protected Source (SourceRoot root, String fname) { | |
296 this.root = root; | |
297 this.fname = fname; | |
298 } | |
299 | |
300 protected void loadLines (InputStream is) throws IOException { | |
301 BufferedReader in = new BufferedReader(new InputStreamReader(is)); | |
302 | |
303 ArrayList<String> l = new ArrayList<String>(); | |
304 for (String line = in.readLine(); line != null; line = in.readLine()) { | |
305 l.add(line); | |
306 } | |
307 in.close(); | |
308 | |
309 if (l.size() > 0) { | |
310 lines = l.toArray(new String[l.size()]); | |
311 } | |
312 } | |
313 | |
314 | |
315 /** | |
316 * this is our sole purpose in life - answer line strings | |
317 * line index is 1-based | |
318 */ | |
319 public String getLine (int i) { | |
320 if ((lines == null) || (i <= 0) || (i > lines.length)) { | |
321 return null; | |
322 } else { | |
323 return lines[i-1]; | |
324 } | |
325 } | |
326 | |
327 public int getLineCount() | |
328 { | |
329 return(lines.length); | |
330 } | |
331 | |
332 public String getPath() { | |
333 return root.toString() + File.separatorChar + fname; | |
334 } | |
335 } |