001: // Copyright (c) 2007 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ../../COPYING.
003:
004: package gnu.text;
005:
006: import java.io.*;
007: import java.net.*;
008: import gnu.lists.FString;
009: import gnu.mapping.*;
010:
011: /** A Path that wraps a URI.
012: * The URI can be a java.net.URI, or a String, if compiled without URI support.
013: */
014:
015: public class URIPath extends Path
016: /* #ifdef JAVA2 */
017: /* #ifdef JAVA5 */
018: // implements Comparable<URIPath>
019: /* #else */
020: implements Comparable
021: /* #endif */
022: /* #endif */
023: {
024: /* #ifdef use:java.net.URI */
025: URI uri;
026:
027: URIPath(URI uri) {
028: this .uri = uri;
029: }
030:
031: /* #else */
032: // String uri;
033: // protected URIPath (String uri) { this.uri = uri; }
034: /* #endif */
035:
036: public static URIPath coerceToURIPathOrNull(Object path) {
037: if (path instanceof URIPath)
038: return (URIPath) path;
039: if (path instanceof URL)
040: return URLPath.valueOf((URL) path);
041: /* #ifdef use:java.net.URI */
042: if (path instanceof URI)
043: return URIPath.valueOf((URI) path);
044: /* #endif */
045: String str;
046: if (path instanceof File || path instanceof Path
047: || path instanceof FString)
048: str = path.toString();
049: else if (path instanceof String)
050: str = (String) path;
051: else
052: return null;
053: return URIPath.valueOf(str);
054: }
055:
056: public static URIPath makeURI(Object arg) {
057: URIPath path = coerceToURIPathOrNull(arg);
058: if (path == null)
059: throw new WrongType((String) null, WrongType.ARG_CAST, arg,
060: "URI");
061: return path;
062: }
063:
064: /* #ifdef use:java.net.URI */
065: public static URIPath valueOf(URI uri) {
066: return new URIPath(uri);
067: }
068:
069: /* #endif */
070:
071: public static URIPath valueOf(String uri) {
072: /* #ifdef use:java.net.URI */
073: try {
074: return new URIStringPath(new URI(encodeForUri(uri, 'I')),
075: uri);
076: } catch (Throwable ex) {
077: throw WrappedException.wrapIfNeeded(ex);
078: }
079: /* #else */
080: // return new URIPath(uri);
081: /* #endif */
082: }
083:
084: public boolean isAbsolute() {
085: /* #ifdef use:java.net.URI */
086: return uri.isAbsolute();
087: /* #else */
088: // return Path.uriSchemeSpecified(uri);
089: /* #endif */
090: }
091:
092: public boolean exists() {
093: try {
094: URLConnection conn = toURL().openConnection();
095: if (conn instanceof HttpURLConnection)
096: return (((HttpURLConnection) conn).getResponseCode() == HttpURLConnection.HTTP_OK);
097: else
098: return conn.getLastModified() != 0;
099: } catch (Throwable ex) {
100: return false;
101: }
102: }
103:
104: public long getLastModified() {
105: return URLPath.getLastModified(toURL());
106: }
107:
108: public long getContentLength() {
109: return URLPath.getContentLength(toURL());
110: }
111:
112: /* #ifdef use:java.net.URI */
113: public URI toURI() {
114: return uri;
115: }
116:
117: public String toURIString() {
118: return uri.toString();
119: }
120:
121: /* #else */
122: // public String toURI () { return uri; }
123: // public String toURIString () { return uri; }
124: /* #endif */
125:
126: public Path resolve(String rstr) {
127: if (Path.uriSchemeSpecified(rstr))
128: return URIPath.valueOf(rstr);
129: char fileSep = File.separatorChar;
130: if (fileSep != '/') {
131: // Check for Windows absolute filename.
132: if (rstr.length() >= 2
133: && ((rstr.charAt(1) == ':' && Character
134: .isLetter(rstr.charAt(0))) || (rstr
135: .charAt(0) == fileSep && rstr.charAt(1) == fileSep))) {
136: return FilePath.valueOf(new File(rstr));
137: }
138: rstr = rstr.replace(fileSep, '/');
139: }
140: /* #ifdef use:java.net.URI */
141: URI resolved;
142: try {
143: resolved = uri.resolve(new URI(null, rstr, null));
144: } catch (Throwable ex) {
145: throw WrappedException.wrapIfNeeded(ex);
146: }
147:
148: /* #else */
149: // /* The following is an appximation of URI's resolve method. */
150: // /* For example, it doesn't simplify "../" to "". */
151: // String sbase = uri;
152: // int lastSl = sbase.lastIndexOf('/');
153: // StringBuffer sbuf = new StringBuffer(sbase);
154: // if (lastSl >= 0)
155: // sbuf.setLength(lastSl+1);
156: // else
157: // sbuf.append('/');
158: // if (rstr.length() > 0 && rstr.charAt(0) == '/')
159: // {
160: // /* Rstr is an absolute file name, but doesn't have a uri scheme. */
161: // int baseLen = sbase.length();
162: // int pathStart = Path.uriSchemeLength(sbase);
163: // if (pathStart <= 1)
164: // return URIPath.valueOf(rstr);
165: // pathStart++;
166: // /* Add the "authority" - usually a host-name. */
167: // if (pathStart + 1 < baseLen
168: // && sbase.charAt(pathStart) == '/'
169: // && sbase.charAt(pathStart+1) == '/')
170: // {
171: // int p2 = sbase.indexOf('/', pathStart+2);
172: // if (p2 < 0)
173: // p2 = baseLen; // ? append '/'? FIXME
174: // pathStart = p2;
175: // }
176: // sbuf.setLength(pathStart);
177: // }
178: // sbuf.append(rstr);
179: // String resolved = sbuf.toString();
180: /* #endif */
181: return URIPath.valueOf(resolved);
182: }
183:
184: public int compareTo(URIPath path) {
185: return uri.compareTo(path.uri);
186: }
187:
188: /* #ifndef JAVA5 */
189: public int compareTo(Object obj) {
190: return compareTo((URIPath) obj);
191: }
192:
193: /* #endif */
194:
195: public boolean equals(Object obj) {
196: return obj instanceof URIPath
197: && uri.equals(((URIPath) obj).uri);
198: }
199:
200: public int hashCode() {
201: return uri.hashCode();
202: }
203:
204: public String toString() {
205: return toURIString();
206: }
207:
208: public URL toURL() {
209: return Path.toURL(uri.toString());
210: }
211:
212: public InputStream openInputStream() throws IOException {
213: // If relative and base is a File, should be a File? FIXME
214: return URLPath.openInputStream(toURL());
215: }
216:
217: public OutputStream openOutputStream() throws IOException {
218: return URLPath.openOutputStream(toURL());
219: }
220:
221: public String getScheme() {
222: /* #ifdef use:java.net.URI */
223: return uri.getScheme();
224: /* #else */
225: // return Path.uriSchemeSpecified(uri) ? toURL().getProtocol() : null;
226: /* #endif */
227: }
228:
229: public String getHost() {
230: /* #ifdef use:java.net.URI */
231: return uri.getHost();
232: /* #else */
233: // return Path.uriSchemeSpecified(uri) ? toURL().getHost() : null;
234: /* #endif */
235: }
236:
237: public String getAuthority() {
238: /* #ifdef use:java.net.URI */
239: return uri.getAuthority();
240: /* #else */
241: // return Path.uriSchemeSpecified(uri) ? toURL().getAuthority() : null;
242: /* #endif */
243: }
244:
245: public String getUserInfo() {
246: /* #ifdef use:java.net.URI */
247: return uri.getUserInfo();
248: /* #else */
249: // return Path.uriSchemeSpecified(uri) ? toURL().getUserInfo() : null;
250: /* #endif */
251: }
252:
253: public int getPort() {
254: /* #ifdef use:java.net.URI */
255: return uri.getPort();
256: /* #else */
257: // return Path.uriSchemeSpecified(uri) ? toURL().getPort() : -1;
258: /* #endif */
259: }
260:
261: public String getPath() {
262: /* #ifdef use:java.net.URI */
263: return uri.getPath();
264: /* #else */
265: // return toURL().getFile();
266: /* #endif */
267: }
268:
269: public String getQuery() {
270: /* #ifdef use:java.net.URI */
271: return uri.getQuery();
272: /* #else */
273: // return toURL().getQuery();
274: /* #endif */
275: }
276:
277: public String getFragment() {
278: /* #ifdef use:java.net.URI */
279: return uri.getFragment();
280: /* #else */
281: // int hash = uri.lastIndexOf('#');
282: // return hash < 0 ? null : uri.substring(hash+1);
283: /* #endif */
284: }
285:
286: public Path getCanonical() {
287: if (isAbsolute()) {
288: /* #ifdef use:java.net.URI */
289: URI norm = uri.normalize();
290: if (norm == uri)
291: return this ;
292: return valueOf(norm);
293: /* #else */
294: // return this; // FIXME!
295: /* #endif */
296: } else
297: return getAbsolute().getCanonical();
298: }
299:
300: public static String encodeForUri(String str, char mode) {
301: StringBuffer sbuf = new StringBuffer();
302: int len = str.length();
303: for (int i = 0; i < len;) {
304: int ch = str.charAt(i++);
305: // Check for surrogate.
306: if (ch >= 0xD800 && ch < 0xDC00 && i < len)
307: ch = (ch - 0xD800) * 0x400 + (str.charAt(i++) - 0xDC00)
308: + 0x10000;
309: if (mode == 'H' ? ch >= 32 && ch <= 126
310: : ((ch >= 'a' && ch <= 'z')
311: || (ch >= 'A' && ch <= 'Z')
312: || (ch >= '0' && ch <= '9') || ch == '-'
313: || ch == '_' || ch == '.' || ch == '~' || (mode == 'I' && (ch == ';'
314: || ch == '/'
315: || ch == '?'
316: || ch == ':'
317: || ch == '*'
318: || ch == '\''
319: || ch == '('
320: || ch == ')'
321: || ch == '@'
322: || ch == '&'
323: || ch == '='
324: || ch == '+'
325: || ch == '$'
326: || ch == ','
327: || ch == '['
328: || ch == ']'
329: || ch == '#' || ch == '!' || ch == '%'))))
330: sbuf.append((char) ch);
331: else {
332: int pos = sbuf.length();
333: int nbytes = 0;
334: int needed = ch < (1 << 7) ? 1 : ch < (1 << 11) ? 2
335: : ch < (1 << 16) ? 3 : 4;
336: do {
337: // We insert encodings for the bytes in right-to-left order.
338: int availbits = nbytes == 0 ? 7 : 6 - nbytes;
339: int b;
340: if (ch < (1 << availbits)) {
341: // The rest fits: handling first bytes.
342: b = ch;
343: if (nbytes > 0)
344: b |= (0xff80 >> nbytes) & 0xff;
345: ch = 0;
346: } else {
347: b = 0x80 | (ch & 0x3f);
348: ch >>= 6;
349: }
350: nbytes++;
351: for (int j = 0; j <= 1; j++) {
352: int hex = b & 15;
353: sbuf.insert(pos, (char) (hex <= 9 ? hex + '0'
354: : hex - 10 + 'A'));
355: b >>= 4;
356: }
357: sbuf.insert(pos, '%');
358: } while (ch != 0);
359: }
360: }
361: return sbuf.toString();
362: }
363: }
364:
365: /* #ifdef use:java.net.URI */
366: /** A URIPath that also remembers the "orginal" (unencoded) String. */
367: class URIStringPath extends URIPath {
368: String uriString;
369:
370: public String toURIString() {
371: return uriString;
372: }
373:
374: public URIStringPath(URI uri, String uriString) {
375: super (uri);
376: this .uriString = uriString;
377: }
378: }
379: /* #endif */
|