FileLocator.java revision 608:7e06bf1dcb09
1/* 2 * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 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 * Licensed Materials - Property of IBM 27 * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997,1998 28 * RMI-IIOP v1.0 29 * 30 */ 31 32package com.sun.tools.corba.se.idl.som.cff; 33 34import java.lang.Exception; 35import java.lang.String; 36import java.lang.System; 37import java.io.BufferedInputStream; 38import java.io.DataInputStream; 39import java.io.File; 40import java.io.FileInputStream; 41import java.io.FileNotFoundException; 42import java.io.InputStream; 43import java.io.IOException; 44import java.util.Locale; 45import java.util.NoSuchElementException; 46import java.util.Properties; 47import java.util.StringTokenizer; 48import java.util.zip.*; 49 50/** 51 * FileLocator is an abstract class (one that cannot be instantiated) that 52 * provides class methods for finding files in the directories or zip 53 * archives that make up the CLASSPATH. 54 * 55 * @author Larry K. Raper 56 */ 57public abstract class FileLocator extends Object { 58 59 /* Class variables */ 60 61 62 static final Properties pp = System.getProperties (); 63 static final String classPath = pp.getProperty ("java.class.path", "."); 64 static final String pathSeparator = pp.getProperty ("path.separator", ";"); 65 66 /* Instance variables */ 67 68 /* [None, no instances of this class are ever instantiated.] */ 69 70 /** 71 * locateClassFile returns a DataInputStream with mark/reset 72 * capability that can be used to read the requested class file. The 73 * CLASSPATH is used to locate the class. 74 * 75 * @param classFileName The name of the class to locate. The class name 76 * should be given in fully-qualified form, for example: 77 * <pre> 78 * java.lang.Object 79 * java.io.DataInputStream 80 * </pre> 81 * 82 * @exception java.io.FileNotFoundException The requested class file 83 * could not be found. 84 * @exception java.io.IOException The requested class file 85 * could not be opened. 86 */ 87 public static DataInputStream locateClassFile (String classFileName) 88 throws FileNotFoundException, IOException { 89 90 boolean notFound = true; 91 StringTokenizer st; 92 String path = ""; 93 String pathNameForm; 94 File cf = null; 95 NamedDataInputStream result; 96 97 st = new StringTokenizer (classPath, pathSeparator, false); 98 pathNameForm = classFileName.replace ('.', File.separatorChar) + 99 ".class"; 100 101 while (st.hasMoreTokens () && notFound) { 102 103 try {path = st.nextToken ();} 104 catch (NoSuchElementException nse) {break;} 105 int pLen = path.length (); 106 String pathLast4 = pLen > 3 ? path.substring (pLen - 4) : ""; 107 if (pathLast4.equalsIgnoreCase (".zip") || 108 pathLast4.equalsIgnoreCase (".jar")) { 109 110 try { 111 112 result = locateInZipFile (path, classFileName, true, true); 113 if (result == null) 114 continue; 115 return (DataInputStream) result; 116 117 } catch (ZipException zfe) { 118 continue; 119 } catch (IOException ioe) { 120 continue; 121 } 122 123 } else { 124 try {cf = new File (path + File.separator + pathNameForm); 125 } catch (NullPointerException npe) { continue; } 126 if ((cf != null) && cf.exists ()) 127 notFound = false; 128 } 129 } 130 131 if (notFound) { 132 133 /* Make one last attempt to find the file in the current 134 * directory 135 */ 136 137 int lastdot = classFileName.lastIndexOf ('.'); 138 String simpleName = 139 (lastdot >= 0) ? classFileName.substring (lastdot+1) : 140 classFileName; 141 142 result = new NamedDataInputStream (new BufferedInputStream ( 143 new FileInputStream (simpleName + ".class")), 144 simpleName + ".class", false); 145 return (DataInputStream) result; 146 } 147 148 result = new NamedDataInputStream (new BufferedInputStream ( 149 new FileInputStream (cf)), path + File.separator + pathNameForm, 150 false); 151 return (DataInputStream) result; 152 153 } 154 155 /** 156 * locateLocaleSpecificFileInClassPath returns a DataInputStream that 157 * can be used to read the requested file, but the name of the file is 158 * determined using information from the current locale and the supplied 159 * file name (which is treated as a "base" name, and is supplemented with 160 * country and language related suffixes, obtained from the current 161 * locale). The CLASSPATH is used to locate the file. 162 * 163 * @param fileName The name of the file to locate. The file name 164 * may be qualified with a partial path name, using '/' as the separator 165 * character or using separator characters appropriate for the host file 166 * system, in which case each directory or zip file in the CLASSPATH will 167 * be used as a base for finding the fully-qualified file. 168 * Here is an example of how the supplied fileName is used as a base 169 * for locating a locale-specific file: 170 * 171 * <pre> 172 * Supplied fileName: a/b/c/x.y, current locale: US English 173 * 174 * Look first for: a/b/c/x_en_US.y 175 * (if that fails) Look next for: a/b/c/x_en.y 176 * (if that fails) Look last for: a/b/c/x.y 177 * 178 * All elements of the class path are searched for each name, 179 * before the next possible name is tried. 180 * </pre> 181 * 182 * @exception java.io.FileNotFoundException The requested class file 183 * could not be found. 184 * @exception java.io.IOException The requested class file 185 * could not be opened. 186 */ 187 public static DataInputStream locateLocaleSpecificFileInClassPath ( 188 String fileName) throws FileNotFoundException, IOException { 189 190 String localeSuffix = "_" + Locale.getDefault ().toString (); 191 int lastSlash = fileName.lastIndexOf ('/'); 192 int lastDot = fileName.lastIndexOf ('.'); 193 String fnFront, fnEnd; 194 DataInputStream result = null; 195 boolean lastAttempt = false; 196 197 if ((lastDot > 0) && (lastDot > lastSlash)) { 198 fnFront = fileName.substring (0, lastDot); 199 fnEnd = fileName.substring (lastDot); 200 } else { 201 fnFront = fileName; 202 fnEnd = ""; 203 } 204 205 while (true) { 206 if (lastAttempt) 207 result = locateFileInClassPath (fileName); 208 else try { 209 result = locateFileInClassPath (fnFront + localeSuffix + fnEnd); 210 } catch (Exception e) { /* ignore */ } 211 if ((result != null) || lastAttempt) 212 break; 213 int lastUnderbar = localeSuffix.lastIndexOf ('_'); 214 if (lastUnderbar > 0) 215 localeSuffix = localeSuffix.substring (0, lastUnderbar); 216 else 217 lastAttempt = true; 218 } 219 return result; 220 221 } 222 223 /** 224 * locateFileInClassPath returns a DataInputStream that can be used 225 * to read the requested file. The CLASSPATH is used to locate the file. 226 * 227 * @param fileName The name of the file to locate. The file name 228 * may be qualified with a partial path name, using '/' as the separator 229 * character or using separator characters appropriate for the host file 230 * system, in which case each directory or zip file in the CLASSPATH will 231 * be used as a base for finding the fully-qualified file. 232 * 233 * @exception java.io.FileNotFoundException The requested class file 234 * could not be found. 235 * @exception java.io.IOException The requested class file 236 * could not be opened. 237 */ 238 public static DataInputStream locateFileInClassPath (String fileName) 239 throws FileNotFoundException, IOException { 240 241 boolean notFound = true; 242 StringTokenizer st; 243 String path = ""; 244 File cf = null; 245 NamedDataInputStream result; 246 247 String zipEntryName = File.separatorChar == '/' ? fileName : 248 fileName.replace (File.separatorChar, '/'); 249 250 String localFileName = File.separatorChar == '/' ? fileName : 251 fileName.replace ('/', File.separatorChar); 252 253 st = new StringTokenizer (classPath, pathSeparator, false); 254 255 while (st.hasMoreTokens () && notFound) { 256 257 try {path = st.nextToken ();} 258 catch (NoSuchElementException nse) {break;} 259 int pLen = path.length (); 260 String pathLast4 = pLen > 3 ? path.substring (pLen - 4) : ""; 261 if (pathLast4.equalsIgnoreCase (".zip") || 262 pathLast4.equalsIgnoreCase (".jar")) { 263 264 try { 265 266 result = locateInZipFile (path, zipEntryName, false, false); 267 if (result == null) 268 continue; 269 return (DataInputStream) result; 270 271 } catch (ZipException zfe) { 272 continue; 273 } catch (IOException ioe) { 274 continue; 275 } 276 277 } else { 278 try {cf = new File (path + File.separator + localFileName); 279 } catch (NullPointerException npe) { continue; } 280 if ((cf != null) && cf.exists ()) 281 notFound = false; 282 } 283 } 284 285 if (notFound) { 286 287 /* Make one last attempt to find the file in the current 288 * directory 289 */ 290 291 int lastpart = localFileName.lastIndexOf (File.separator); 292 String simpleName = 293 (lastpart >= 0) ? localFileName.substring (lastpart+1) : 294 localFileName; 295 296 result = new NamedDataInputStream (new BufferedInputStream ( 297 new FileInputStream (simpleName)), simpleName, false); 298 return (DataInputStream) result; 299 } 300 301 result = new NamedDataInputStream (new BufferedInputStream ( 302 new FileInputStream (cf)), path + File.separator + localFileName, 303 false); 304 return (DataInputStream) result; 305 306 } 307 308 /** 309 * Returns the fully qualified file name associated with the passed 310 * DataInputStream <i>if the DataInputStream was created using one 311 * of the static locate methods supplied with this class</i>, otherwise 312 * returns a zero length string. 313 */ 314 public static String getFileNameFromStream (DataInputStream ds) { 315 316 if (ds instanceof NamedDataInputStream) 317 return ((NamedDataInputStream) ds).fullyQualifiedFileName; 318 return ""; 319 320 } 321 322 /** 323 * Returns an indication of whether the passed DataInputStream is 324 * associated with a member of a zip file <i>if the DataInputStream was 325 * created using one of the static locate methods supplied with this 326 * class</i>, otherwise returns false. 327 */ 328 public static boolean isZipFileAssociatedWithStream (DataInputStream ds) { 329 330 if (ds instanceof NamedDataInputStream) 331 return ((NamedDataInputStream) ds).inZipFile; 332 return false; 333 334 } 335 336 private static NamedDataInputStream locateInZipFile (String zipFileName, 337 String fileName, boolean wantClass, boolean buffered) 338 throws ZipException, IOException { 339 340 ZipFile zf; 341 ZipEntry ze; 342 zf = new ZipFile (zipFileName); 343 344 if (zf == null) 345 return null; 346 String zeName = wantClass ? 347 fileName.replace ('.', '/') + ".class" : 348 fileName; 349 350 // This code works with JDK 1.0 level SUN zip classes 351 // 352 353 // ze = zf.get (zeName); 354 // if (ze == null) 355 // return null; 356 // return new NamedDataInputStream ( 357 // new BufferedInputStream (new ZipInputStream (ze)), 358 // zipFileName + '(' +zeName + ')', true); 359 360 // This code works with JDK 1.0.2 and JDK 1.1 level SUN zip classes 361 // 362 363 ze = zf.getEntry (zeName); 364 if (ze == null) { 365 zf.close(); // D55355, D56419 366 zf = null; 367 return null; 368 } 369 InputStream istream = zf.getInputStream(ze); 370 if (buffered) 371 istream = new BufferedInputStream(istream); 372 return new NamedDataInputStream (istream, 373 zipFileName + '(' + zeName + ')', true); 374 375 } 376 377} 378 379/** 380 * This class is used to associate a filename with a DataInputStream 381 * The host platform's file naming conventions are assumed for the filename. 382 * 383 * @author Larry K. Raper 384 * 385 */ 386/* default access */ class NamedDataInputStream extends DataInputStream { 387 388 /* Instance variables */ 389 390 /** 391 * The name of the file associated with the DataInputStream. 392 */ 393 public String fullyQualifiedFileName; 394 395 /** 396 * Indicates whether or not the file is contained in a .zip file. 397 */ 398 public boolean inZipFile; 399 400 /* Constructors */ 401 402 protected NamedDataInputStream (InputStream in, String fullyQualifiedName, 403 boolean inZipFile) { 404 405 super (in); 406 this.fullyQualifiedFileName = fullyQualifiedName; 407 this.inZipFile = inZipFile; 408 409 } 410 411} 412