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