1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xml.internal.utils; 23 24 import java.io.File; 25 26 import javax.xml.transform.TransformerException; 27 28 import com.sun.org.apache.xml.internal.utils.URI.MalformedURIException; 29 30 /** 31 * This class is used to resolve relative URIs and SystemID 32 * strings into absolute URIs. 33 * 34 * <p>This is a generic utility for resolving URIs, other than the 35 * fact that it's declared to throw TransformerException. Please 36 * see code comments for details on how resolution is performed.</p> 37 * @xsl.usage internal 38 */ 39 public class SystemIDResolver 40 { 41 42 /** 43 * Get an absolute URI from a given relative URI (local path). 44 * 45 * <p>The relative URI is a local filesystem path. The path can be 46 * absolute or relative. If it is a relative path, it is resolved relative 47 * to the system property "user.dir" if it is available; if not (i.e. in an 48 * Applet perhaps which throws SecurityException) then we just return the 49 * relative path. The space and backslash characters are also replaced to 50 * generate a good absolute URI.</p> 51 * 52 * @param localPath The relative URI to resolve 53 * 54 * @return Resolved absolute URI 55 */ getAbsoluteURIFromRelative(String localPath)56 public static String getAbsoluteURIFromRelative(String localPath) 57 { 58 if (localPath == null || localPath.length() == 0) 59 return ""; 60 61 // If the local path is a relative path, then it is resolved against 62 // the "user.dir" system property. 63 String absolutePath = localPath; 64 if (!isAbsolutePath(localPath)) 65 { 66 try 67 { 68 absolutePath = getAbsolutePathFromRelativePath(localPath); 69 } 70 // user.dir not accessible from applet 71 catch (SecurityException se) 72 { 73 return "file:" + localPath; 74 } 75 } 76 77 String urlString; 78 if (null != absolutePath) 79 { 80 if (absolutePath.startsWith(File.separator)) 81 urlString = "file://" + absolutePath; 82 else 83 urlString = "file:///" + absolutePath; 84 } 85 else 86 urlString = "file:" + localPath; 87 88 return replaceChars(urlString); 89 } 90 91 /** 92 * Return an absolute path from a relative path. 93 * 94 * @param relativePath A relative path 95 * @return The absolute path 96 */ getAbsolutePathFromRelativePath(String relativePath)97 private static String getAbsolutePathFromRelativePath(String relativePath) 98 { 99 return new File(relativePath).getAbsolutePath(); 100 } 101 102 /** 103 * Return true if the systemId denotes an absolute URI . 104 * 105 * @param systemId The systemId string 106 * @return true if the systemId is an an absolute URI 107 */ isAbsoluteURI(String systemId)108 public static boolean isAbsoluteURI(String systemId) 109 { 110 /** http://www.ietf.org/rfc/rfc2396.txt 111 * Authors should be aware that a path segment which contains a colon 112 * character cannot be used as the first segment of a relative URI path 113 * (e.g., "this:that"), because it would be mistaken for a scheme name. 114 **/ 115 /** 116 * %REVIEW% Can we assume here that systemId is a valid URI? 117 * It looks like we cannot ( See discussion of this common problem in 118 * Bugzilla Bug 22777 ). 119 **/ 120 //"fix" for Bugzilla Bug 22777 121 if(isWindowsAbsolutePath(systemId)){ 122 return false; 123 } 124 125 final int fragmentIndex = systemId.indexOf('#'); 126 final int queryIndex = systemId.indexOf('?'); 127 final int slashIndex = systemId.indexOf('/'); 128 final int colonIndex = systemId.indexOf(':'); 129 130 //finding substring before '#', '?', and '/' 131 int index = systemId.length() -1; 132 if(fragmentIndex > 0) 133 index = fragmentIndex; 134 if((queryIndex > 0) && (queryIndex <index)) 135 index = queryIndex; 136 if((slashIndex > 0) && (slashIndex <index)) 137 index = slashIndex; 138 // return true if there is ':' before '#', '?', and '/' 139 return ((colonIndex >0) && (colonIndex<index)); 140 141 } 142 143 /** 144 * Return true if the local path is an absolute path. 145 * 146 * @param systemId The path string 147 * @return true if the path is absolute 148 */ isAbsolutePath(String systemId)149 public static boolean isAbsolutePath(String systemId) 150 { 151 if(systemId == null) 152 return false; 153 final File file = new File(systemId); 154 return file.isAbsolute(); 155 156 } 157 158 /** 159 * Return true if the local path is a Windows absolute path. 160 * 161 * @param systemId The path string 162 * @return true if the path is a Windows absolute path 163 */ isWindowsAbsolutePath(String systemId)164 private static boolean isWindowsAbsolutePath(String systemId) 165 { 166 if(!isAbsolutePath(systemId)) 167 return false; 168 // On Windows, an absolute path starts with "[drive_letter]:\". 169 if (systemId.length() > 2 170 && systemId.charAt(1) == ':' 171 && Character.isLetter(systemId.charAt(0)) 172 && (systemId.charAt(2) == '\\' || systemId.charAt(2) == '/')) 173 return true; 174 else 175 return false; 176 } 177 178 /** 179 * Replace spaces with "%20" and backslashes with forward slashes in 180 * the input string to generate a well-formed URI string. 181 * 182 * @param str The input string 183 * @return The string after conversion 184 */ replaceChars(String str)185 private static String replaceChars(String str) 186 { 187 StringBuffer buf = new StringBuffer(str); 188 int length = buf.length(); 189 for (int i = 0; i < length; i++) 190 { 191 char currentChar = buf.charAt(i); 192 // Replace space with "%20" 193 if (currentChar == ' ') 194 { 195 buf.setCharAt(i, '%'); 196 buf.insert(i+1, "20"); 197 length = length + 2; 198 i = i + 2; 199 } 200 // Replace backslash with forward slash 201 else if (currentChar == '\\') 202 { 203 buf.setCharAt(i, '/'); 204 } 205 } 206 207 return buf.toString(); 208 } 209 210 /** 211 * Take a SystemID string and try to turn it into a good absolute URI. 212 * 213 * @param systemId A URI string, which may be absolute or relative. 214 * 215 * @return The resolved absolute URI 216 */ getAbsoluteURI(String systemId)217 public static String getAbsoluteURI(String systemId) 218 { 219 String absoluteURI = systemId; 220 if (isAbsoluteURI(systemId)) 221 { 222 // Only process the systemId if it starts with "file:". 223 if (systemId.startsWith("file:")) 224 { 225 String str = systemId.substring(5); 226 227 // Resolve the absolute path if the systemId starts with "file:///" 228 // or "file:/". Don't do anything if it only starts with "file://". 229 if (str != null && str.startsWith("/")) 230 { 231 if (str.startsWith("///") || !str.startsWith("//")) 232 { 233 // A Windows path containing a drive letter can be relative. 234 // A Unix path starting with "file:/" is always absolute. 235 int secondColonIndex = systemId.indexOf(':', 5); 236 if (secondColonIndex > 0) 237 { 238 String localPath = systemId.substring(secondColonIndex-1); 239 try { 240 if (!isAbsolutePath(localPath)) 241 absoluteURI = systemId.substring(0, secondColonIndex-1) + 242 getAbsolutePathFromRelativePath(localPath); 243 } 244 catch (SecurityException se) { 245 return systemId; 246 } 247 } 248 } 249 } 250 else 251 { 252 return getAbsoluteURIFromRelative(systemId.substring(5)); 253 } 254 255 return replaceChars(absoluteURI); 256 } 257 else 258 return systemId; 259 } 260 else 261 return getAbsoluteURIFromRelative(systemId); 262 263 } 264 265 266 /** 267 * Take a SystemID string and try to turn it into a good absolute URI. 268 * 269 * @param urlString SystemID string 270 * @param base The URI string used as the base for resolving the systemID 271 * 272 * @return The resolved absolute URI 273 * @throws TransformerException thrown if the string can't be turned into a URI. 274 */ getAbsoluteURI(String urlString, String base)275 public static String getAbsoluteURI(String urlString, String base) 276 throws TransformerException 277 { 278 if (base == null) 279 return getAbsoluteURI(urlString); 280 281 String absoluteBase = getAbsoluteURI(base); 282 URI uri = null; 283 try 284 { 285 URI baseURI = new URI(absoluteBase); 286 uri = new URI(baseURI, urlString); 287 } 288 catch (MalformedURIException mue) 289 { 290 throw new TransformerException(mue); 291 } 292 293 return replaceChars(uri.toString()); 294 } 295 296 } 297