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