KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > vfs > provider > UriParser


1 /*
2  * Copyright 2002-2005 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 package org.apache.commons.vfs.provider;
17
18 import org.apache.commons.vfs.FileName;
19 import org.apache.commons.vfs.FileSystemException;
20 import org.apache.commons.vfs.FileType;
21 import org.apache.commons.vfs.VFS;
22
23 /**
24  * Utilities for dealing with URIs. See RFC 2396 for details.
25  *
26  * @author <a HREF="mailto:adammurdoch@apache.org">Adam Murdoch</a>
27  * @version $Revision: 1.4 $ $Date: 2005-10-13 21:11:33 +0200 (Do, 13 Okt
28  * 2005) $
29  */

30 public final class UriParser
31 {
32     /**
33      * The normalised separator to use.
34      */

35     private static final char SEPARATOR_CHAR = FileName.SEPARATOR_CHAR;
36
37     /**
38      * The set of valid separators. These are all converted to the normalised
39      * one. Does <i>not</i> contain the normalised separator
40      */

41     // public static final char[] separators = {'\\'};
42
public static final char TRANS_SEPARATOR = '\\';
43
44     private UriParser()
45     {
46     }
47
48     /**
49      * Extracts the first element of a path.
50      */

51     public static String JavaDoc extractFirstElement(final StringBuffer JavaDoc name)
52     {
53         final int len = name.length();
54         if (len < 1)
55         {
56             return null;
57         }
58         int startPos = 0;
59         if (name.charAt(0) == SEPARATOR_CHAR)
60         {
61             startPos = 1;
62         }
63         for (int pos = startPos; pos < len; pos++)
64         {
65             if (name.charAt(pos) == SEPARATOR_CHAR)
66             {
67                 // Found a separator
68
final String JavaDoc elem = name.substring(startPos, pos);
69                 name.delete(startPos, pos + 1);
70                 return elem;
71             }
72         }
73
74         // No separator
75
final String JavaDoc elem = name.substring(startPos);
76         name.setLength(0);
77         return elem;
78     }
79
80     /**
81      * Normalises a path. Does the following:
82      * <ul>
83      * <li>Removes empty path elements.
84      * <li>Handles '.' and '..' elements.
85      * <li>Removes trailing separator.
86      * </ul>
87      *
88      * Its assumed that the separators are already fixed.
89      *
90      * @see #fixSeparators
91      */

92     public static FileType normalisePath(final StringBuffer JavaDoc path)
93             throws FileSystemException
94     {
95         FileType fileType = FileType.FOLDER;
96         if (path.length() == 0)
97         {
98             return fileType;
99         }
100
101         if (path.charAt(path.length() - 1) != '/')
102         {
103             fileType = FileType.FILE;
104         }
105
106         // Adjust separators
107
// fixSeparators(path);
108

109         // Determine the start of the first element
110
int startFirstElem = 0;
111         if (path.charAt(0) == SEPARATOR_CHAR)
112         {
113             if (path.length() == 1)
114             {
115                 return fileType;
116             }
117             startFirstElem = 1;
118         }
119
120         // Iterate over each element
121
int startElem = startFirstElem;
122         int maxlen = path.length();
123         while (startElem < maxlen)
124         {
125             // Find the end of the element
126
int endElem = startElem;
127             for (; endElem < maxlen && path.charAt(endElem) != SEPARATOR_CHAR; endElem++)
128             {
129             }
130
131             final int elemLen = endElem - startElem;
132             if (elemLen == 0)
133             {
134                 // An empty element - axe it
135
path.delete(endElem, endElem + 1);
136                 maxlen = path.length();
137                 continue;
138             }
139             if (elemLen == 1 && path.charAt(startElem) == '.')
140             {
141                 // A '.' element - axe it
142
path.delete(startElem, endElem + 1);
143                 maxlen = path.length();
144                 continue;
145             }
146             if (elemLen == 2 && path.charAt(startElem) == '.'
147                     && path.charAt(startElem + 1) == '.')
148             {
149                 // A '..' element - remove the previous element
150
if (startElem == startFirstElem)
151                 {
152                     // Previous element is missing
153
throw new FileSystemException(
154                             "vfs.provider/invalid-relative-path.error");
155                 }
156
157                 // Find start of previous element
158
int pos = startElem - 2;
159                 for (; pos >= 0 && path.charAt(pos) != SEPARATOR_CHAR; pos--)
160                 {
161                 }
162                 startElem = pos + 1;
163
164                 path.delete(startElem, endElem + 1);
165                 maxlen = path.length();
166                 continue;
167             }
168
169             // A regular element
170
startElem = endElem + 1;
171         }
172
173         // Remove trailing separator
174
if (!VFS.isUriStyle())
175         {
176             if (maxlen > 0 && path.charAt(maxlen - 1) == SEPARATOR_CHAR
177                     && maxlen > 1)
178             {
179                 path.delete(maxlen - 1, maxlen);
180             }
181         }
182
183         return fileType;
184     }
185
186     /**
187      * Normalises the separators in a name.
188      */

189     public static boolean fixSeparators(final StringBuffer JavaDoc name)
190     {
191         boolean changed = false;
192         final int maxlen = name.length();
193         for (int i = 0; i < maxlen; i++)
194         {
195             final char ch = name.charAt(i);
196             if (ch == TRANS_SEPARATOR)
197             {
198                 name.setCharAt(i, SEPARATOR_CHAR);
199                 changed = true;
200             }
201         }
202         return changed;
203     }
204
205     /**
206      * Extracts the scheme from a URI.
207      *
208      * @param uri
209      * The URI.
210      * @return The scheme name. Returns null if there is no scheme.
211      */

212     public static String JavaDoc extractScheme(final String JavaDoc uri)
213     {
214         return extractScheme(uri, null);
215     }
216
217     /**
218      * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from
219      * the front of the URI.
220      *
221      * @param uri
222      * The URI.
223      * @param buffer
224      * Returns the remainder of the URI.
225      * @return The scheme name. Returns null if there is no scheme.
226      */

227     public static String JavaDoc extractScheme(final String JavaDoc uri,
228             final StringBuffer JavaDoc buffer)
229     {
230         if (buffer != null)
231         {
232             buffer.setLength(0);
233             buffer.append(uri);
234         }
235
236         final int maxPos = uri.length();
237         for (int pos = 0; pos < maxPos; pos++)
238         {
239             final char ch = uri.charAt(pos);
240
241             if (ch == ':')
242             {
243                 // Found the end of the scheme
244
final String JavaDoc scheme = uri.substring(0, pos);
245                 if (buffer != null)
246                 {
247                     buffer.delete(0, pos + 1);
248                 }
249                 return scheme;
250             }
251
252             if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
253             {
254                 // A scheme character
255
continue;
256             }
257             if (pos > 0
258                     && ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.'))
259             {
260                 // A scheme character (these are not allowed as the first
261
// character of the scheme, but can be used as subsequent
262
// characters.
263
continue;
264             }
265
266             // Not a scheme character
267
break;
268         }
269
270         // No scheme in URI
271
return null;
272     }
273
274     /**
275      * Removes %nn encodings from a string.
276      */

277     public static String JavaDoc decode(final String JavaDoc encodedStr)
278             throws FileSystemException
279     {
280         if (encodedStr == null)
281         {
282             return null;
283         }
284         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(encodedStr);
285         decode(buffer, 0, buffer.length());
286         return buffer.toString();
287     }
288
289     /**
290      * Removes %nn encodings from a string.
291      */

292     public static void decode(final StringBuffer JavaDoc buffer, final int offset,
293             final int length) throws FileSystemException
294     {
295         int index = offset;
296         int count = length;
297         for (; count > 0; count--, index++)
298         {
299             final char ch = buffer.charAt(index);
300             if (ch != '%')
301             {
302                 continue;
303             }
304             if (count < 3)
305             {
306                 throw new FileSystemException(
307                         "vfs.provider/invalid-escape-sequence.error", buffer
308                                 .substring(index, index + count));
309             }
310
311             // Decode
312
int dig1 = Character.digit(buffer.charAt(index + 1), 16);
313             int dig2 = Character.digit(buffer.charAt(index + 2), 16);
314             if (dig1 == -1 || dig2 == -1)
315             {
316                 throw new FileSystemException(
317                         "vfs.provider/invalid-escape-sequence.error", buffer
318                                 .substring(index, index + 3));
319             }
320             char value = (char) (dig1 << 4 | dig2);
321
322             // Replace
323
buffer.setCharAt(index, value);
324             buffer.delete(index + 1, index + 3);
325             count -= 2;
326         }
327     }
328
329     /**
330      * Encodes and appends a string to a StringBuffer.
331      */

332     public static void appendEncoded(final StringBuffer JavaDoc buffer,
333             final String JavaDoc unencodedValue, final char[] reserved)
334     {
335         final int offset = buffer.length();
336         buffer.append(unencodedValue);
337         encode(buffer, offset, unencodedValue.length(), reserved);
338     }
339
340     /**
341      * Encodes a set of reserved characters in a StringBuffer, using the URI %nn
342      * encoding. Always encodes % characters.
343      */

344     public static void encode(final StringBuffer JavaDoc buffer, final int offset,
345             final int length, final char[] reserved)
346     {
347         int index = offset;
348         int count = length;
349         for (; count > 0; index++, count--)
350         {
351             final char ch = buffer.charAt(index);
352             boolean match = (ch == '%');
353             if (reserved != null)
354             {
355                 for (int i = 0; !match && i < reserved.length; i++)
356                 {
357                     if (ch == reserved[i])
358                     {
359                         match = true;
360                     }
361                 }
362             }
363             if (match)
364             {
365                 // Encode
366
char[] digits =
367                 { Character.forDigit(((ch >> 4) & 0xF), 16),
368                         Character.forDigit((ch & 0xF), 16) };
369                 buffer.setCharAt(index, '%');
370                 buffer.insert(index + 1, digits);
371                 index += 2;
372             }
373         }
374     }
375
376     /**
377      * Removes %nn encodings from a string.
378      */

379     public static String JavaDoc encode(final String JavaDoc decodedStr)
380     {
381         return encode(decodedStr, null);
382     }
383
384     public static String JavaDoc encode(final String JavaDoc decodedStr, final char[] reserved)
385     {
386         if (decodedStr == null)
387         {
388             return null;
389         }
390         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(decodedStr);
391         encode(buffer, 0, buffer.length(), reserved);
392         return buffer.toString();
393     }
394
395     public static String JavaDoc[] encode(String JavaDoc[] strings)
396     {
397         if (strings == null)
398         {
399             return null;
400         }
401         for (int i = 0; i < strings.length; i++)
402         {
403             strings[i] = encode(strings[i]);
404         }
405         return strings;
406     }
407
408     public static void checkUriEncoding(String JavaDoc uri) throws FileSystemException
409     {
410         decode(uri);
411     }
412
413     public static void canonicalizePath(StringBuffer JavaDoc buffer, int offset,
414             int length, FileNameParser fileNameParser)
415             throws FileSystemException
416     {
417         int index = offset;
418         int count = length;
419         for (; count > 0; count--, index++)
420         {
421             final char ch = buffer.charAt(index);
422             if (ch == '%')
423             {
424                 if (count < 3)
425                 {
426                     throw new FileSystemException(
427                             "vfs.provider/invalid-escape-sequence.error",
428                             buffer.substring(index, index + count));
429                 }
430
431                 // Decode
432
int dig1 = Character.digit(buffer.charAt(index + 1), 16);
433                 int dig2 = Character.digit(buffer.charAt(index + 2), 16);
434                 if (dig1 == -1 || dig2 == -1)
435                 {
436                     throw new FileSystemException(
437                             "vfs.provider/invalid-escape-sequence.error",
438                             buffer.substring(index, index + 3));
439                 }
440                 char value = (char) (dig1 << 4 | dig2);
441
442                 boolean match = (value == '%')
443                         || (fileNameParser != null && fileNameParser
444                                 .encodeCharacter(value));
445
446                 if (match)
447                 {
448                     // this is a reserved character, not allowed to decode
449
index += 2;
450                     count -= 2;
451                     continue;
452                 }
453
454                 // Replace
455
buffer.setCharAt(index, value);
456                 buffer.delete(index + 1, index + 3);
457                 count -= 2;
458             }
459             else if (fileNameParser.encodeCharacter(ch))
460             {
461                 // Encode
462
char[] digits =
463                 { Character.forDigit(((ch >> 4) & 0xF), 16),
464                         Character.forDigit((ch & 0xF), 16) };
465                 buffer.setCharAt(index, '%');
466                 buffer.insert(index + 1, digits);
467                 index += 2;
468             }
469         }
470     }
471
472     public static String JavaDoc extractQueryString(StringBuffer JavaDoc name)
473     {
474         for (int pos = 0; pos < name.length(); pos++)
475         {
476             if (name.charAt(pos) == '?')
477             {
478                 String JavaDoc queryString = name.substring(pos + 1);
479                 name.delete(pos, name.length());
480                 return queryString;
481             }
482         }
483
484         return null;
485     }
486 }
487
Popular Tags