001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: SystemIDResolver.java,v 1.24 2004/02/17 04:21:14 minchau Exp $
018: */
019: package org.apache.xml.utils;
020:
021: import java.io.File;
022:
023: import javax.xml.transform.TransformerException;
024:
025: import org.apache.xml.utils.URI.MalformedURIException;
026:
027: /**
028: * This class is used to resolve relative URIs and SystemID
029: * strings into absolute URIs.
030: *
031: * <p>This is a generic utility for resolving URIs, other than the
032: * fact that it's declared to throw TransformerException. Please
033: * see code comments for details on how resolution is performed.</p>
034: * @xsl.usage internal
035: */
036: public class SystemIDResolver {
037:
038: /**
039: * Get an absolute URI from a given relative URI (local path).
040: *
041: * <p>The relative URI is a local filesystem path. The path can be
042: * absolute or relative. If it is a relative path, it is resolved relative
043: * to the system property "user.dir" if it is available; if not (i.e. in an
044: * Applet perhaps which throws SecurityException) then we just return the
045: * relative path. The space and backslash characters are also replaced to
046: * generate a good absolute URI.</p>
047: *
048: * @param localPath The relative URI to resolve
049: *
050: * @return Resolved absolute URI
051: */
052: public static String getAbsoluteURIFromRelative(String localPath) {
053: if (localPath == null || localPath.length() == 0)
054: return "";
055:
056: // If the local path is a relative path, then it is resolved against
057: // the "user.dir" system property.
058: String absolutePath = localPath;
059: if (!isAbsolutePath(localPath)) {
060: try {
061: absolutePath = getAbsolutePathFromRelativePath(localPath);
062: }
063: // user.dir not accessible from applet
064: catch (SecurityException se) {
065: return "file:" + localPath;
066: }
067: }
068:
069: String urlString;
070: if (null != absolutePath) {
071: if (absolutePath.startsWith(File.separator))
072: urlString = "file://" + absolutePath;
073: else
074: urlString = "file:///" + absolutePath;
075: } else
076: urlString = "file:" + localPath;
077:
078: return replaceChars(urlString);
079: }
080:
081: /**
082: * Return an absolute path from a relative path.
083: *
084: * @param relativePath A relative path
085: * @return The absolute path
086: */
087: private static String getAbsolutePathFromRelativePath(
088: String relativePath) {
089: return new File(relativePath).getAbsolutePath();
090: }
091:
092: /**
093: * Return true if the systemId denotes an absolute URI .
094: *
095: * @param systemId The systemId string
096: * @return true if the systemId is an an absolute URI
097: */
098: public static boolean isAbsoluteURI(String systemId) {
099: /** http://www.ietf.org/rfc/rfc2396.txt
100: * Authors should be aware that a path segment which contains a colon
101: * character cannot be used as the first segment of a relative URI path
102: * (e.g., "this:that"), because it would be mistaken for a scheme name.
103: **/
104: /**
105: * %REVIEW% Can we assume here that systemId is a valid URI?
106: * It looks like we cannot ( See discussion of this common problem in
107: * Bugzilla Bug 22777 ).
108: **/
109: //"fix" for Bugzilla Bug 22777
110: if (isWindowsAbsolutePath(systemId)) {
111: return false;
112: }
113:
114: final int fragmentIndex = systemId.indexOf('#');
115: final int queryIndex = systemId.indexOf('?');
116: final int slashIndex = systemId.indexOf('/');
117: final int colonIndex = systemId.indexOf(':');
118:
119: //finding substring before '#', '?', and '/'
120: int index = systemId.length() - 1;
121: if (fragmentIndex > 0)
122: index = fragmentIndex;
123: if ((queryIndex > 0) && (queryIndex < index))
124: index = queryIndex;
125: if ((slashIndex > 0) && (slashIndex < index))
126: index = slashIndex;
127: // return true if there is ':' before '#', '?', and '/'
128: return ((colonIndex > 0) && (colonIndex < index));
129:
130: }
131:
132: /**
133: * Return true if the local path is an absolute path.
134: *
135: * @param systemId The path string
136: * @return true if the path is absolute
137: */
138: public static boolean isAbsolutePath(String systemId) {
139: if (systemId == null)
140: return false;
141: final File file = new File(systemId);
142: return file.isAbsolute();
143:
144: }
145:
146: /**
147: * Return true if the local path is a Windows absolute path.
148: *
149: * @param systemId The path string
150: * @return true if the path is a Windows absolute path
151: */
152: private static boolean isWindowsAbsolutePath(String systemId) {
153: if (!isAbsolutePath(systemId))
154: return false;
155: // On Windows, an absolute path starts with "[drive_letter]:\".
156: if (systemId.length() > 2
157: && systemId.charAt(1) == ':'
158: && Character.isLetter(systemId.charAt(0))
159: && (systemId.charAt(2) == '\\' || systemId.charAt(2) == '/'))
160: return true;
161: else
162: return false;
163: }
164:
165: /**
166: * Replace spaces with "%20" and backslashes with forward slashes in
167: * the input string to generate a well-formed URI string.
168: *
169: * @param str The input string
170: * @return The string after conversion
171: */
172: private static String replaceChars(String str) {
173: StringBuffer buf = new StringBuffer(str);
174: int length = buf.length();
175: for (int i = 0; i < length; i++) {
176: char currentChar = buf.charAt(i);
177: // Replace space with "%20"
178: if (currentChar == ' ') {
179: buf.setCharAt(i, '%');
180: buf.insert(i + 1, "20");
181: length = length + 2;
182: i = i + 2;
183: }
184: // Replace backslash with forward slash
185: else if (currentChar == '\\') {
186: buf.setCharAt(i, '/');
187: }
188: }
189:
190: return buf.toString();
191: }
192:
193: /**
194: * Take a SystemID string and try to turn it into a good absolute URI.
195: *
196: * @param systemId A URI string, which may be absolute or relative.
197: *
198: * @return The resolved absolute URI
199: */
200: public static String getAbsoluteURI(String systemId) {
201: String absoluteURI = systemId;
202: if (isAbsoluteURI(systemId)) {
203: // Only process the systemId if it starts with "file:".
204: if (systemId.startsWith("file:")) {
205: String str = systemId.substring(5);
206:
207: // Resolve the absolute path if the systemId starts with "file:///"
208: // or "file:/". Don't do anything if it only starts with "file://".
209: if (str != null && str.startsWith("/")) {
210: if (str.startsWith("///") || !str.startsWith("//")) {
211: // A Windows path containing a drive letter can be relative.
212: // A Unix path starting with "file:/" is always absolute.
213: int secondColonIndex = systemId.indexOf(':', 5);
214: if (secondColonIndex > 0) {
215: String localPath = systemId
216: .substring(secondColonIndex - 1);
217: try {
218: if (!isAbsolutePath(localPath))
219: absoluteURI = systemId.substring(0,
220: secondColonIndex - 1)
221: + getAbsolutePathFromRelativePath(localPath);
222: } catch (SecurityException se) {
223: return systemId;
224: }
225: }
226: }
227: } else {
228: return getAbsoluteURIFromRelative(systemId
229: .substring(5));
230: }
231:
232: return replaceChars(absoluteURI);
233: } else
234: return systemId;
235: } else
236: return getAbsoluteURIFromRelative(systemId);
237:
238: }
239:
240: /**
241: * Take a SystemID string and try to turn it into a good absolute URI.
242: *
243: * @param urlString SystemID string
244: * @param base The URI string used as the base for resolving the systemID
245: *
246: * @return The resolved absolute URI
247: * @throws TransformerException thrown if the string can't be turned into a URI.
248: */
249: public static String getAbsoluteURI(String urlString, String base)
250: throws TransformerException {
251: if (base == null)
252: return getAbsoluteURI(urlString);
253:
254: String absoluteBase = getAbsoluteURI(base);
255: URI uri = null;
256: try {
257: URI baseURI = new URI(absoluteBase);
258: uri = new URI(baseURI, urlString);
259: } catch (MalformedURIException mue) {
260: throw new TransformerException(mue);
261: }
262:
263: return replaceChars(uri.toString());
264: }
265:
266: }
|