Frames | No Frames |
1: /* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net 2: Copyright (C) 1999, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.java.net.protocol.jar; 40: 41: import gnu.java.lang.CPStringBuilder; 42: 43: import gnu.java.net.URLParseError; 44: 45: import java.io.IOException; 46: import java.net.MalformedURLException; 47: import java.net.URL; 48: import java.net.URLConnection; 49: import java.net.URLStreamHandler; 50: import java.util.ArrayList; 51: import java.util.Iterator; 52: import java.util.StringTokenizer; 53: 54: /** 55: * @author Kresten Krab Thorup (krab@gnu.org) 56: */ 57: public class Handler extends URLStreamHandler 58: { 59: /** 60: * A do nothing constructor 61: */ 62: public Handler() 63: { 64: } 65: 66: /** 67: * This method returs a new JarURLConnection for the specified URL 68: * 69: * @param url The URL to return a connection for 70: * 71: * @return The URLConnection 72: * 73: * @exception IOException If an error occurs 74: */ 75: protected URLConnection openConnection(URL url) throws IOException 76: { 77: return new Connection(url); 78: } 79: 80: /** 81: * This method overrides URLStreamHandler's for parsing url of protocol "jar" 82: * 83: * @param url The URL object in which to store the results 84: * @param url_string The String-ized URL to parse 85: * @param start The position in the string to start scanning from 86: * @param end The position in the string to stop scanning 87: */ 88: protected void parseURL (URL url, String url_string, int start, int end) 89: { 90: // This method does not throw an exception or return a value. Thus our 91: // strategy when we encounter an error in parsing is to return without 92: // doing anything. 93: String file = url.getFile(); 94: 95: if (!file.equals("")) 96: { //has context url 97: url_string = url_string.substring (start, end); 98: if (url_string.startsWith("/")) 99: { //url string is an absolute path 100: int idx = file.lastIndexOf ("!/"); 101: 102: if (idx < 0) 103: throw new URLParseError("no !/ in spec"); 104: 105: file = file.substring (0, idx + 1) + url_string; 106: } 107: else if (url_string.length() > 0) 108: { 109: int idx = file.lastIndexOf ("/"); 110: if (idx == -1) //context path is weird 111: file = "/" + url_string; 112: else if (idx == (file.length() - 1)) 113: //just concatenate two parts 114: file = file + url_string; 115: else 116: // according to Java API Documentation, here is a little different 117: // with URLStreamHandler.parseURL 118: // but JDK seems doesn't handle it well 119: file = file.substring(0, idx + 1) + url_string; 120: } 121: 122: setURL (url, "jar", url.getHost(), url.getPort(), flat(file), null); 123: return; 124: } 125: 126: // Bunches of things should be true. Make sure. 127: if (end < start) 128: return; 129: if (end - start < 2) 130: return; 131: if (start > url_string.length()) 132: return; 133: 134: // Skip remains of protocol 135: url_string = url_string.substring (start, end); 136: 137: int jar_stop; 138: if ((jar_stop = url_string.indexOf("!/")) < 0) 139: throw new URLParseError("no !/ in spec"); 140: 141: try 142: { 143: new URL(url_string.substring (0, jar_stop)); 144: } 145: catch (MalformedURLException e) 146: { 147: throw new URLParseError("invalid inner URL: " + e.getMessage()); 148: } 149: 150: if (!url.getProtocol().equals ("jar") ) 151: throw new URLParseError("unexpected protocol " + url.getProtocol()); 152: 153: setURL (url, "jar", url.getHost(), url.getPort(), url_string, null); 154: } 155: 156: /** 157: * Makes the given jar url string 'flat' by removing any . and .. from 158: * jar file path because ZipFile entries can only handle flat paths. 159: * Inside jar files '/' is always the path separator. 160: */ 161: private static String flat(String url_string) 162: { 163: int jar_stop = url_string.indexOf("!/"); 164: String jar_path = url_string.substring(jar_stop + 1, url_string.length()); 165: 166: if (jar_path.indexOf("/.") < 0) 167: return url_string; 168: 169: ArrayList<String> tokens = new ArrayList<String>(); 170: StringTokenizer st = new StringTokenizer(jar_path, "/"); 171: while (st.hasMoreTokens()) 172: { 173: String token = st.nextToken(); 174: if (token.equals(".")) 175: continue; 176: else if (token.equals("..")) 177: { 178: if (! tokens.isEmpty()) 179: tokens.remove(tokens.size() - 1); 180: } 181: else 182: tokens.add(token); 183: } 184: 185: CPStringBuilder path = new CPStringBuilder(url_string.length()); 186: path.append(url_string.substring(0, jar_stop + 1)); 187: 188: Iterator<String> it = tokens.iterator(); 189: while (it.hasNext()) 190: path.append('/').append(it.next()); 191: 192: return path.toString(); 193: } 194: 195: /** 196: * This method converts a Jar URL object into a String. 197: * 198: * @param url The URL object to convert 199: */ 200: protected String toExternalForm (URL url) 201: { 202: String file = url.getFile(); 203: String ref = url.getRef(); 204: 205: // return "jar:" + file; 206: // Performance!!: 207: // Do the concatenation manually to avoid resize StringBuffer's 208: // internal buffer. The length of ref is not taken into consideration 209: // as it's a rare path. 210: CPStringBuilder sb = new CPStringBuilder (file.length() + 5); 211: sb.append ("jar:"); 212: sb.append (file); 213: if (ref != null) 214: sb.append('#').append(ref); 215: return sb.toString(); 216: } 217: }