• 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: URI.java 468655 2006-10-28 07:12:06Z minchau $
20  */
21 package org.apache.xml.utils;
22 
23 import java.io.IOException;
24 import java.io.Serializable;
25 
26 import org.apache.xml.res.XMLErrorResources;
27 import org.apache.xml.res.XMLMessages;
28 
29 /**
30  * A class to represent a Uniform Resource Identifier (URI). This class
31  * is designed to handle the parsing of URIs and provide access to
32  * the various components (scheme, host, port, userinfo, path, query
33  * string and fragment) that may constitute a URI.
34  * <p>
35  * Parsing of a URI specification is done according to the URI
36  * syntax described in RFC 2396
37  * <http://www.ietf.org/rfc/rfc2396.txt?number=2396>. Every URI consists
38  * of a scheme, followed by a colon (':'), followed by a scheme-specific
39  * part. For URIs that follow the "generic URI" syntax, the scheme-
40  * specific part begins with two slashes ("//") and may be followed
41  * by an authority segment (comprised of user information, host, and
42  * port), path segment, query segment and fragment. Note that RFC 2396
43  * no longer specifies the use of the parameters segment and excludes
44  * the "user:password" syntax as part of the authority segment. If
45  * "user:password" appears in a URI, the entire user/password string
46  * is stored as userinfo.
47  * <p>
48  * For URIs that do not follow the "generic URI" syntax (e.g. mailto),
49  * the entire scheme-specific part is treated as the "path" portion
50  * of the URI.
51  * <p>
52  * Note that, unlike the java.net.URL class, this class does not provide
53  * any built-in network access functionality nor does it provide any
54  * scheme-specific functionality (for example, it does not know a
55  * default port for a specific scheme). Rather, it only knows the
56  * grammar and basic set of operations that can be applied to a URI.
57  *
58  *
59  */
60 public class URI implements Serializable
61 {
62     static final long serialVersionUID = 7096266377907081897L;
63 
64   /**
65    * MalformedURIExceptions are thrown in the process of building a URI
66    * or setting fields on a URI when an operation would result in an
67    * invalid URI specification.
68    *
69    */
70   public static class MalformedURIException extends IOException
71   {
72 
73     /**
74      * Constructs a <code>MalformedURIException</code> with no specified
75      * detail message.
76      */
MalformedURIException()77     public MalformedURIException()
78     {
79       super();
80     }
81 
82     /**
83      * Constructs a <code>MalformedURIException</code> with the
84      * specified detail message.
85      *
86      * @param p_msg the detail message.
87      */
MalformedURIException(String p_msg)88     public MalformedURIException(String p_msg)
89     {
90       super(p_msg);
91     }
92   }
93 
94   /** reserved characters */
95   private static final String RESERVED_CHARACTERS = ";/?:@&=+$,";
96 
97   /**
98    * URI punctuation mark characters - these, combined with
99    *   alphanumerics, constitute the "unreserved" characters
100    */
101   private static final String MARK_CHARACTERS = "-_.!~*'() ";
102 
103   /** scheme can be composed of alphanumerics and these characters */
104   private static final String SCHEME_CHARACTERS = "+-.";
105 
106   /**
107    * userinfo can be composed of unreserved, escaped and these
108    *   characters
109    */
110   private static final String USERINFO_CHARACTERS = ";:&=+$,";
111 
112   /** Stores the scheme (usually the protocol) for this URI.
113    *  @serial */
114   private String m_scheme = null;
115 
116   /** If specified, stores the userinfo for this URI; otherwise null.
117    *  @serial */
118   private String m_userinfo = null;
119 
120   /** If specified, stores the host for this URI; otherwise null.
121    *  @serial */
122   private String m_host = null;
123 
124   /** If specified, stores the port for this URI; otherwise -1.
125    *  @serial */
126   private int m_port = -1;
127 
128   /** If specified, stores the path for this URI; otherwise null.
129    *  @serial */
130   private String m_path = null;
131 
132   /**
133    * If specified, stores the query string for this URI; otherwise
134    *   null.
135    * @serial
136    */
137   private String m_queryString = null;
138 
139   /** If specified, stores the fragment for this URI; otherwise null.
140    *  @serial */
141   private String m_fragment = null;
142 
143   /** Indicate whether in DEBUG mode          */
144   private static boolean DEBUG = false;
145 
146   /**
147    * Construct a new and uninitialized URI.
148    */
URI()149   public URI(){}
150 
151   /**
152    * Construct a new URI from another URI. All fields for this URI are
153    * set equal to the fields of the URI passed in.
154    *
155    * @param p_other the URI to copy (cannot be null)
156    */
URI(URI p_other)157   public URI(URI p_other)
158   {
159     initialize(p_other);
160   }
161 
162   /**
163    * Construct a new URI from a URI specification string. If the
164    * specification follows the "generic URI" syntax, (two slashes
165    * following the first colon), the specification will be parsed
166    * accordingly - setting the scheme, userinfo, host,port, path, query
167    * string and fragment fields as necessary. If the specification does
168    * not follow the "generic URI" syntax, the specification is parsed
169    * into a scheme and scheme-specific part (stored as the path) only.
170    *
171    * @param p_uriSpec the URI specification string (cannot be null or
172    *                  empty)
173    *
174    * @throws MalformedURIException if p_uriSpec violates any syntax
175    *                                   rules
176    */
URI(String p_uriSpec)177   public URI(String p_uriSpec) throws MalformedURIException
178   {
179     this((URI) null, p_uriSpec);
180   }
181 
182   /**
183    * Construct a new URI from a base URI and a URI specification string.
184    * The URI specification string may be a relative URI.
185    *
186    * @param p_base the base URI (cannot be null if p_uriSpec is null or
187    *               empty)
188    * @param p_uriSpec the URI specification string (cannot be null or
189    *                  empty if p_base is null)
190    *
191    * @throws MalformedURIException if p_uriSpec violates any syntax
192    *                                  rules
193    */
URI(URI p_base, String p_uriSpec)194   public URI(URI p_base, String p_uriSpec) throws MalformedURIException
195   {
196     initialize(p_base, p_uriSpec);
197   }
198 
199   /**
200    * Construct a new URI that does not follow the generic URI syntax.
201    * Only the scheme and scheme-specific part (stored as the path) are
202    * initialized.
203    *
204    * @param p_scheme the URI scheme (cannot be null or empty)
205    * @param p_schemeSpecificPart the scheme-specific part (cannot be
206    *                             null or empty)
207    *
208    * @throws MalformedURIException if p_scheme violates any
209    *                                  syntax rules
210    */
URI(String p_scheme, String p_schemeSpecificPart)211   public URI(String p_scheme, String p_schemeSpecificPart)
212           throws MalformedURIException
213   {
214 
215     if (p_scheme == null || p_scheme.trim().length() == 0)
216     {
217       throw new MalformedURIException(
218         "Cannot construct URI with null/empty scheme!");
219     }
220 
221     if (p_schemeSpecificPart == null
222             || p_schemeSpecificPart.trim().length() == 0)
223     {
224       throw new MalformedURIException(
225         "Cannot construct URI with null/empty scheme-specific part!");
226     }
227 
228     setScheme(p_scheme);
229     setPath(p_schemeSpecificPart);
230   }
231 
232   /**
233    * Construct a new URI that follows the generic URI syntax from its
234    * component parts. Each component is validated for syntax and some
235    * basic semantic checks are performed as well.  See the individual
236    * setter methods for specifics.
237    *
238    * @param p_scheme the URI scheme (cannot be null or empty)
239    * @param p_host the hostname or IPv4 address for the URI
240    * @param p_path the URI path - if the path contains '?' or '#',
241    *               then the query string and/or fragment will be
242    *               set from the path; however, if the query and
243    *               fragment are specified both in the path and as
244    *               separate parameters, an exception is thrown
245    * @param p_queryString the URI query string (cannot be specified
246    *                      if path is null)
247    * @param p_fragment the URI fragment (cannot be specified if path
248    *                   is null)
249    *
250    * @throws MalformedURIException if any of the parameters violates
251    *                                  syntax rules or semantic rules
252    */
URI(String p_scheme, String p_host, String p_path, String p_queryString, String p_fragment)253   public URI(String p_scheme, String p_host, String p_path, String p_queryString, String p_fragment)
254           throws MalformedURIException
255   {
256     this(p_scheme, null, p_host, -1, p_path, p_queryString, p_fragment);
257   }
258 
259   /**
260    * Construct a new URI that follows the generic URI syntax from its
261    * component parts. Each component is validated for syntax and some
262    * basic semantic checks are performed as well.  See the individual
263    * setter methods for specifics.
264    *
265    * @param p_scheme the URI scheme (cannot be null or empty)
266    * @param p_userinfo the URI userinfo (cannot be specified if host
267    *                   is null)
268    * @param p_host the hostname or IPv4 address for the URI
269    * @param p_port the URI port (may be -1 for "unspecified"; cannot
270    *               be specified if host is null)
271    * @param p_path the URI path - if the path contains '?' or '#',
272    *               then the query string and/or fragment will be
273    *               set from the path; however, if the query and
274    *               fragment are specified both in the path and as
275    *               separate parameters, an exception is thrown
276    * @param p_queryString the URI query string (cannot be specified
277    *                      if path is null)
278    * @param p_fragment the URI fragment (cannot be specified if path
279    *                   is null)
280    *
281    * @throws MalformedURIException if any of the parameters violates
282    *                                  syntax rules or semantic rules
283    */
URI(String p_scheme, String p_userinfo, String p_host, int p_port, String p_path, String p_queryString, String p_fragment)284   public URI(String p_scheme, String p_userinfo, String p_host, int p_port, String p_path, String p_queryString, String p_fragment)
285           throws MalformedURIException
286   {
287 
288     if (p_scheme == null || p_scheme.trim().length() == 0)
289     {
290       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_SCHEME_REQUIRED, null)); //"Scheme is required!");
291     }
292 
293     if (p_host == null)
294     {
295       if (p_userinfo != null)
296       {
297         throw new MalformedURIException(
298           XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_USERINFO_IF_NO_HOST, null)); //"Userinfo may not be specified if host is not specified!");
299       }
300 
301       if (p_port != -1)
302       {
303         throw new MalformedURIException(
304           XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_PORT_IF_NO_HOST, null)); //"Port may not be specified if host is not specified!");
305       }
306     }
307 
308     if (p_path != null)
309     {
310       if (p_path.indexOf('?') != -1 && p_queryString != null)
311       {
312         throw new MalformedURIException(
313           XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_QUERY_STRING_IN_PATH, null)); //"Query string cannot be specified in path and query string!");
314       }
315 
316       if (p_path.indexOf('#') != -1 && p_fragment != null)
317       {
318         throw new MalformedURIException(
319           XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_FRAGMENT_STRING_IN_PATH, null)); //"Fragment cannot be specified in both the path and fragment!");
320       }
321     }
322 
323     setScheme(p_scheme);
324     setHost(p_host);
325     setPort(p_port);
326     setUserinfo(p_userinfo);
327     setPath(p_path);
328     setQueryString(p_queryString);
329     setFragment(p_fragment);
330   }
331 
332   /**
333    * Initialize all fields of this URI from another URI.
334    *
335    * @param p_other the URI to copy (cannot be null)
336    */
initialize(URI p_other)337   private void initialize(URI p_other)
338   {
339 
340     m_scheme = p_other.getScheme();
341     m_userinfo = p_other.getUserinfo();
342     m_host = p_other.getHost();
343     m_port = p_other.getPort();
344     m_path = p_other.getPath();
345     m_queryString = p_other.getQueryString();
346     m_fragment = p_other.getFragment();
347   }
348 
349   /**
350    * Initializes this URI from a base URI and a URI specification string.
351    * See RFC 2396 Section 4 and Appendix B for specifications on parsing
352    * the URI and Section 5 for specifications on resolving relative URIs
353    * and relative paths.
354    *
355    * @param p_base the base URI (may be null if p_uriSpec is an absolute
356    *               URI)
357    * @param p_uriSpec the URI spec string which may be an absolute or
358    *                  relative URI (can only be null/empty if p_base
359    *                  is not null)
360    *
361    * @throws MalformedURIException if p_base is null and p_uriSpec
362    *                                  is not an absolute URI or if
363    *                                  p_uriSpec violates syntax rules
364    */
initialize(URI p_base, String p_uriSpec)365   private void initialize(URI p_base, String p_uriSpec)
366           throws MalformedURIException
367   {
368 
369     if (p_base == null
370             && (p_uriSpec == null || p_uriSpec.trim().length() == 0))
371     {
372       throw new MalformedURIException(
373         XMLMessages.createXMLMessage(XMLErrorResources.ER_CANNOT_INIT_URI_EMPTY_PARMS, null)); //"Cannot initialize URI with empty parameters.");
374     }
375 
376     // just make a copy of the base if spec is empty
377     if (p_uriSpec == null || p_uriSpec.trim().length() == 0)
378     {
379       initialize(p_base);
380 
381       return;
382     }
383 
384     String uriSpec = p_uriSpec.trim();
385     int uriSpecLen = uriSpec.length();
386     int index = 0;
387 
388     // check for scheme
389     int colonIndex = uriSpec.indexOf(':');
390     if (colonIndex < 0)
391     {
392       if (p_base == null)
393       {
394         throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_SCHEME_IN_URI, new Object[]{uriSpec})); //"No scheme found in URI: "+uriSpec);
395       }
396     }
397     else
398     {
399       initializeScheme(uriSpec);
400       uriSpec = uriSpec.substring(colonIndex+1);
401       // This is a fix for XALANJ-2059.
402       if(m_scheme != null && p_base != null)
403       {
404         // a) If <uriSpec> starts with a slash (/), it means <uriSpec> is absolute
405         //    and p_base can be ignored.
406         //    For example,
407         //    uriSpec = file:/myDIR/myXSLFile.xsl
408         //    p_base = file:/myWork/
409         //
410         //    Here, uriSpec has absolute path after scheme file and :
411         //    Hence p_base can be ignored.
412         //
413         // b) Similarily, according to RFC 2396, uri is resolved for <uriSpec> relative to <p_base>
414         //    if scheme in <uriSpec> is same as scheme in <p_base>, else p_base can be ignored.
415         //
416         // c) if <p_base> is not hierarchical, it can be ignored.
417         //
418         if(uriSpec.startsWith("/") || !m_scheme.equals(p_base.m_scheme) || !p_base.getSchemeSpecificPart().startsWith("/"))
419         {
420           p_base = null;
421         }
422       }
423       // Fix for XALANJ-2059
424       uriSpecLen = uriSpec.length();
425     }
426 
427     // two slashes means generic URI syntax, so we get the authority
428     if (uriSpec.startsWith("//"))
429     {
430       index += 2;
431 
432       int startPos = index;
433 
434       // get authority - everything up to path, query or fragment
435       char testChar = '\0';
436 
437       while (index < uriSpecLen)
438       {
439         testChar = uriSpec.charAt(index);
440 
441         if (testChar == '/' || testChar == '?' || testChar == '#')
442         {
443           break;
444         }
445 
446         index++;
447       }
448 
449       // if we found authority, parse it out, otherwise we set the
450       // host to empty string
451       if (index > startPos)
452       {
453         initializeAuthority(uriSpec.substring(startPos, index));
454       }
455       else
456       {
457         m_host = "";
458       }
459     }
460 
461     initializePath(uriSpec.substring(index));
462 
463     // Resolve relative URI to base URI - see RFC 2396 Section 5.2
464     // In some cases, it might make more sense to throw an exception
465     // (when scheme is specified is the string spec and the base URI
466     // is also specified, for example), but we're just following the
467     // RFC specifications
468     if (p_base != null)
469     {
470 
471       // check to see if this is the current doc - RFC 2396 5.2 #2
472       // note that this is slightly different from the RFC spec in that
473       // we don't include the check for query string being null
474       // - this handles cases where the urispec is just a query
475       // string or a fragment (e.g. "?y" or "#s") -
476       // see <http://www.ics.uci.edu/~fielding/url/test1.html> which
477       // identified this as a bug in the RFC
478       if (m_path.length() == 0 && m_scheme == null && m_host == null)
479       {
480         m_scheme = p_base.getScheme();
481         m_userinfo = p_base.getUserinfo();
482         m_host = p_base.getHost();
483         m_port = p_base.getPort();
484         m_path = p_base.getPath();
485 
486         if (m_queryString == null)
487         {
488           m_queryString = p_base.getQueryString();
489         }
490 
491         return;
492       }
493 
494       // check for scheme - RFC 2396 5.2 #3
495       // if we found a scheme, it means absolute URI, so we're done
496       if (m_scheme == null)
497       {
498         m_scheme = p_base.getScheme();
499       }
500 
501       // check for authority - RFC 2396 5.2 #4
502       // if we found a host, then we've got a network path, so we're done
503       if (m_host == null)
504       {
505         m_userinfo = p_base.getUserinfo();
506         m_host = p_base.getHost();
507         m_port = p_base.getPort();
508       }
509       else
510       {
511         return;
512       }
513 
514       // check for absolute path - RFC 2396 5.2 #5
515       if (m_path.length() > 0 && m_path.startsWith("/"))
516       {
517         return;
518       }
519 
520       // if we get to this point, we need to resolve relative path
521       // RFC 2396 5.2 #6
522       String path = new String();
523       String basePath = p_base.getPath();
524 
525       // 6a - get all but the last segment of the base URI path
526       if (basePath != null)
527       {
528         int lastSlash = basePath.lastIndexOf('/');
529 
530         if (lastSlash != -1)
531         {
532           path = basePath.substring(0, lastSlash + 1);
533         }
534       }
535 
536       // 6b - append the relative URI path
537       path = path.concat(m_path);
538 
539       // 6c - remove all "./" where "." is a complete path segment
540       index = -1;
541 
542       while ((index = path.indexOf("/./")) != -1)
543       {
544         path = path.substring(0, index + 1).concat(path.substring(index + 3));
545       }
546 
547       // 6d - remove "." if path ends with "." as a complete path segment
548       if (path.endsWith("/."))
549       {
550         path = path.substring(0, path.length() - 1);
551       }
552 
553       // 6e - remove all "<segment>/../" where "<segment>" is a complete
554       // path segment not equal to ".."
555       index = -1;
556 
557       int segIndex = -1;
558       String tempString = null;
559 
560       while ((index = path.indexOf("/../")) > 0)
561       {
562         tempString = path.substring(0, path.indexOf("/../"));
563         segIndex = tempString.lastIndexOf('/');
564 
565         if (segIndex != -1)
566         {
567           if (!tempString.substring(segIndex++).equals(".."))
568           {
569             path = path.substring(0, segIndex).concat(path.substring(index
570                     + 4));
571           }
572         }
573       }
574 
575       // 6f - remove ending "<segment>/.." where "<segment>" is a
576       // complete path segment
577       if (path.endsWith("/.."))
578       {
579         tempString = path.substring(0, path.length() - 3);
580         segIndex = tempString.lastIndexOf('/');
581 
582         if (segIndex != -1)
583         {
584           path = path.substring(0, segIndex + 1);
585         }
586       }
587 
588       m_path = path;
589     }
590   }
591 
592   /**
593    * Initialize the scheme for this URI from a URI string spec.
594    *
595    * @param p_uriSpec the URI specification (cannot be null)
596    *
597    * @throws MalformedURIException if URI does not have a conformant
598    *                                  scheme
599    */
initializeScheme(String p_uriSpec)600   private void initializeScheme(String p_uriSpec) throws MalformedURIException
601   {
602 
603     int uriSpecLen = p_uriSpec.length();
604     int index = 0;
605     String scheme = null;
606     char testChar = '\0';
607 
608     while (index < uriSpecLen)
609     {
610       testChar = p_uriSpec.charAt(index);
611 
612       if (testChar == ':' || testChar == '/' || testChar == '?'
613               || testChar == '#')
614       {
615         break;
616       }
617 
618       index++;
619     }
620 
621     scheme = p_uriSpec.substring(0, index);
622 
623     if (scheme.length() == 0)
624     {
625       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_SCHEME_INURI, null)); //"No scheme found in URI.");
626     }
627     else
628     {
629       setScheme(scheme);
630     }
631   }
632 
633   /**
634    * Initialize the authority (userinfo, host and port) for this
635    * URI from a URI string spec.
636    *
637    * @param p_uriSpec the URI specification (cannot be null)
638    *
639    * @throws MalformedURIException if p_uriSpec violates syntax rules
640    */
initializeAuthority(String p_uriSpec)641   private void initializeAuthority(String p_uriSpec)
642           throws MalformedURIException
643   {
644 
645     int index = 0;
646     int start = 0;
647     int end = p_uriSpec.length();
648     char testChar = '\0';
649     String userinfo = null;
650 
651     // userinfo is everything up @
652     if (p_uriSpec.indexOf('@', start) != -1)
653     {
654       while (index < end)
655       {
656         testChar = p_uriSpec.charAt(index);
657 
658         if (testChar == '@')
659         {
660           break;
661         }
662 
663         index++;
664       }
665 
666       userinfo = p_uriSpec.substring(start, index);
667 
668       index++;
669     }
670 
671     // host is everything up to ':'
672     String host = null;
673 
674     start = index;
675 
676     while (index < end)
677     {
678       testChar = p_uriSpec.charAt(index);
679 
680       if (testChar == ':')
681       {
682         break;
683       }
684 
685       index++;
686     }
687 
688     host = p_uriSpec.substring(start, index);
689 
690     int port = -1;
691 
692     if (host.length() > 0)
693     {
694 
695       // port
696       if (testChar == ':')
697       {
698         index++;
699 
700         start = index;
701 
702         while (index < end)
703         {
704           index++;
705         }
706 
707         String portStr = p_uriSpec.substring(start, index);
708 
709         if (portStr.length() > 0)
710         {
711           for (int i = 0; i < portStr.length(); i++)
712           {
713             if (!isDigit(portStr.charAt(i)))
714             {
715               throw new MalformedURIException(
716                 portStr + " is invalid. Port should only contain digits!");
717             }
718           }
719 
720           try
721           {
722             port = Integer.parseInt(portStr);
723           }
724           catch (NumberFormatException nfe)
725           {
726 
727             // can't happen
728           }
729         }
730       }
731     }
732 
733     setHost(host);
734     setPort(port);
735     setUserinfo(userinfo);
736   }
737 
738   /**
739    * Initialize the path for this URI from a URI string spec.
740    *
741    * @param p_uriSpec the URI specification (cannot be null)
742    *
743    * @throws MalformedURIException if p_uriSpec violates syntax rules
744    */
initializePath(String p_uriSpec)745   private void initializePath(String p_uriSpec) throws MalformedURIException
746   {
747 
748     if (p_uriSpec == null)
749     {
750       throw new MalformedURIException(
751         "Cannot initialize path from null string!");
752     }
753 
754     int index = 0;
755     int start = 0;
756     int end = p_uriSpec.length();
757     char testChar = '\0';
758 
759     // path - everything up to query string or fragment
760     while (index < end)
761     {
762       testChar = p_uriSpec.charAt(index);
763 
764       if (testChar == '?' || testChar == '#')
765       {
766         break;
767       }
768 
769       // check for valid escape sequence
770       if (testChar == '%')
771       {
772         if (index + 2 >= end ||!isHex(p_uriSpec.charAt(index + 1))
773                 ||!isHex(p_uriSpec.charAt(index + 2)))
774         {
775           throw new MalformedURIException(
776             XMLMessages.createXMLMessage(XMLErrorResources.ER_PATH_CONTAINS_INVALID_ESCAPE_SEQUENCE, null)); //"Path contains invalid escape sequence!");
777         }
778       }
779       else if (!isReservedCharacter(testChar)
780                &&!isUnreservedCharacter(testChar))
781       {
782         if ('\\' != testChar)
783           throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_PATH_INVALID_CHAR, new Object[]{String.valueOf(testChar)})); //"Path contains invalid character: "
784                                           //+ testChar);
785       }
786 
787       index++;
788     }
789 
790     m_path = p_uriSpec.substring(start, index);
791 
792     // query - starts with ? and up to fragment or end
793     if (testChar == '?')
794     {
795       index++;
796 
797       start = index;
798 
799       while (index < end)
800       {
801         testChar = p_uriSpec.charAt(index);
802 
803         if (testChar == '#')
804         {
805           break;
806         }
807 
808         if (testChar == '%')
809         {
810           if (index + 2 >= end ||!isHex(p_uriSpec.charAt(index + 1))
811                   ||!isHex(p_uriSpec.charAt(index + 2)))
812           {
813             throw new MalformedURIException(
814               "Query string contains invalid escape sequence!");
815           }
816         }
817         else if (!isReservedCharacter(testChar)
818                  &&!isUnreservedCharacter(testChar))
819         {
820           throw new MalformedURIException(
821             "Query string contains invalid character:" + testChar);
822         }
823 
824         index++;
825       }
826 
827       m_queryString = p_uriSpec.substring(start, index);
828     }
829 
830     // fragment - starts with #
831     if (testChar == '#')
832     {
833       index++;
834 
835       start = index;
836 
837       while (index < end)
838       {
839         testChar = p_uriSpec.charAt(index);
840 
841         if (testChar == '%')
842         {
843           if (index + 2 >= end ||!isHex(p_uriSpec.charAt(index + 1))
844                   ||!isHex(p_uriSpec.charAt(index + 2)))
845           {
846             throw new MalformedURIException(
847               "Fragment contains invalid escape sequence!");
848           }
849         }
850         else if (!isReservedCharacter(testChar)
851                  &&!isUnreservedCharacter(testChar))
852         {
853           throw new MalformedURIException(
854             "Fragment contains invalid character:" + testChar);
855         }
856 
857         index++;
858       }
859 
860       m_fragment = p_uriSpec.substring(start, index);
861     }
862   }
863 
864   /**
865    * Get the scheme for this URI.
866    *
867    * @return the scheme for this URI
868    */
getScheme()869   public String getScheme()
870   {
871     return m_scheme;
872   }
873 
874   /**
875    * Get the scheme-specific part for this URI (everything following the
876    * scheme and the first colon). See RFC 2396 Section 5.2 for spec.
877    *
878    * @return the scheme-specific part for this URI
879    */
getSchemeSpecificPart()880   public String getSchemeSpecificPart()
881   {
882 
883     StringBuffer schemespec = new StringBuffer();
884 
885     if (m_userinfo != null || m_host != null || m_port != -1)
886     {
887       schemespec.append("//");
888     }
889 
890     if (m_userinfo != null)
891     {
892       schemespec.append(m_userinfo);
893       schemespec.append('@');
894     }
895 
896     if (m_host != null)
897     {
898       schemespec.append(m_host);
899     }
900 
901     if (m_port != -1)
902     {
903       schemespec.append(':');
904       schemespec.append(m_port);
905     }
906 
907     if (m_path != null)
908     {
909       schemespec.append((m_path));
910     }
911 
912     if (m_queryString != null)
913     {
914       schemespec.append('?');
915       schemespec.append(m_queryString);
916     }
917 
918     if (m_fragment != null)
919     {
920       schemespec.append('#');
921       schemespec.append(m_fragment);
922     }
923 
924     return schemespec.toString();
925   }
926 
927   /**
928    * Get the userinfo for this URI.
929    *
930    * @return the userinfo for this URI (null if not specified).
931    */
getUserinfo()932   public String getUserinfo()
933   {
934     return m_userinfo;
935   }
936 
937   /**
938    * Get the host for this URI.
939    *
940    * @return the host for this URI (null if not specified).
941    */
getHost()942   public String getHost()
943   {
944     return m_host;
945   }
946 
947   /**
948    * Get the port for this URI.
949    *
950    * @return the port for this URI (-1 if not specified).
951    */
getPort()952   public int getPort()
953   {
954     return m_port;
955   }
956 
957   /**
958    * Get the path for this URI (optionally with the query string and
959    * fragment).
960    *
961    * @param p_includeQueryString if true (and query string is not null),
962    *                             then a "?" followed by the query string
963    *                             will be appended
964    * @param p_includeFragment if true (and fragment is not null),
965    *                             then a "#" followed by the fragment
966    *                             will be appended
967    *
968    * @return the path for this URI possibly including the query string
969    *         and fragment
970    */
getPath(boolean p_includeQueryString, boolean p_includeFragment)971   public String getPath(boolean p_includeQueryString,
972                         boolean p_includeFragment)
973   {
974 
975     StringBuffer pathString = new StringBuffer(m_path);
976 
977     if (p_includeQueryString && m_queryString != null)
978     {
979       pathString.append('?');
980       pathString.append(m_queryString);
981     }
982 
983     if (p_includeFragment && m_fragment != null)
984     {
985       pathString.append('#');
986       pathString.append(m_fragment);
987     }
988 
989     return pathString.toString();
990   }
991 
992   /**
993    * Get the path for this URI. Note that the value returned is the path
994    * only and does not include the query string or fragment.
995    *
996    * @return the path for this URI.
997    */
getPath()998   public String getPath()
999   {
1000     return m_path;
1001   }
1002 
1003   /**
1004    * Get the query string for this URI.
1005    *
1006    * @return the query string for this URI. Null is returned if there
1007    *         was no "?" in the URI spec, empty string if there was a
1008    *         "?" but no query string following it.
1009    */
getQueryString()1010   public String getQueryString()
1011   {
1012     return m_queryString;
1013   }
1014 
1015   /**
1016    * Get the fragment for this URI.
1017    *
1018    * @return the fragment for this URI. Null is returned if there
1019    *         was no "#" in the URI spec, empty string if there was a
1020    *         "#" but no fragment following it.
1021    */
getFragment()1022   public String getFragment()
1023   {
1024     return m_fragment;
1025   }
1026 
1027   /**
1028    * Set the scheme for this URI. The scheme is converted to lowercase
1029    * before it is set.
1030    *
1031    * @param p_scheme the scheme for this URI (cannot be null)
1032    *
1033    * @throws MalformedURIException if p_scheme is not a conformant
1034    *                                  scheme name
1035    */
setScheme(String p_scheme)1036   public void setScheme(String p_scheme) throws MalformedURIException
1037   {
1038 
1039     if (p_scheme == null)
1040     {
1041       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_SCHEME_FROM_NULL_STRING, null)); //"Cannot set scheme from null string!");
1042     }
1043 
1044     if (!isConformantSchemeName(p_scheme))
1045     {
1046       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_SCHEME_NOT_CONFORMANT, null)); //"The scheme is not conformant.");
1047     }
1048 
1049     m_scheme = p_scheme.toLowerCase();
1050   }
1051 
1052   /**
1053    * Set the userinfo for this URI. If a non-null value is passed in and
1054    * the host value is null, then an exception is thrown.
1055    *
1056    * @param p_userinfo the userinfo for this URI
1057    *
1058    * @throws MalformedURIException if p_userinfo contains invalid
1059    *                                  characters
1060    */
setUserinfo(String p_userinfo)1061   public void setUserinfo(String p_userinfo) throws MalformedURIException
1062   {
1063 
1064     if (p_userinfo == null)
1065     {
1066       m_userinfo = null;
1067     }
1068     else
1069     {
1070       if (m_host == null)
1071       {
1072         throw new MalformedURIException(
1073           "Userinfo cannot be set when host is null!");
1074       }
1075 
1076       // userinfo can contain alphanumerics, mark characters, escaped
1077       // and ';',':','&','=','+','$',','
1078       int index = 0;
1079       int end = p_userinfo.length();
1080       char testChar = '\0';
1081 
1082       while (index < end)
1083       {
1084         testChar = p_userinfo.charAt(index);
1085 
1086         if (testChar == '%')
1087         {
1088           if (index + 2 >= end ||!isHex(p_userinfo.charAt(index + 1))
1089                   ||!isHex(p_userinfo.charAt(index + 2)))
1090           {
1091             throw new MalformedURIException(
1092               "Userinfo contains invalid escape sequence!");
1093           }
1094         }
1095         else if (!isUnreservedCharacter(testChar)
1096                  && USERINFO_CHARACTERS.indexOf(testChar) == -1)
1097         {
1098           throw new MalformedURIException(
1099             "Userinfo contains invalid character:" + testChar);
1100         }
1101 
1102         index++;
1103       }
1104     }
1105 
1106     m_userinfo = p_userinfo;
1107   }
1108 
1109   /**
1110    * Set the host for this URI. If null is passed in, the userinfo
1111    * field is also set to null and the port is set to -1.
1112    *
1113    * @param p_host the host for this URI
1114    *
1115    * @throws MalformedURIException if p_host is not a valid IP
1116    *                                  address or DNS hostname.
1117    */
setHost(String p_host)1118   public void setHost(String p_host) throws MalformedURIException
1119   {
1120 
1121     if (p_host == null || p_host.trim().length() == 0)
1122     {
1123       m_host = p_host;
1124       m_userinfo = null;
1125       m_port = -1;
1126     }
1127     else if (!isWellFormedAddress(p_host))
1128     {
1129       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_HOST_ADDRESS_NOT_WELLFORMED, null)); //"Host is not a well formed address!");
1130     }
1131 
1132     m_host = p_host;
1133   }
1134 
1135   /**
1136    * Set the port for this URI. -1 is used to indicate that the port is
1137    * not specified, otherwise valid port numbers are  between 0 and 65535.
1138    * If a valid port number is passed in and the host field is null,
1139    * an exception is thrown.
1140    *
1141    * @param p_port the port number for this URI
1142    *
1143    * @throws MalformedURIException if p_port is not -1 and not a
1144    *                                  valid port number
1145    */
setPort(int p_port)1146   public void setPort(int p_port) throws MalformedURIException
1147   {
1148 
1149     if (p_port >= 0 && p_port <= 65535)
1150     {
1151       if (m_host == null)
1152       {
1153         throw new MalformedURIException(
1154           XMLMessages.createXMLMessage(XMLErrorResources.ER_PORT_WHEN_HOST_NULL, null)); //"Port cannot be set when host is null!");
1155       }
1156     }
1157     else if (p_port != -1)
1158     {
1159       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_INVALID_PORT, null)); //"Invalid port number!");
1160     }
1161 
1162     m_port = p_port;
1163   }
1164 
1165   /**
1166    * Set the path for this URI. If the supplied path is null, then the
1167    * query string and fragment are set to null as well. If the supplied
1168    * path includes a query string and/or fragment, these fields will be
1169    * parsed and set as well. Note that, for URIs following the "generic
1170    * URI" syntax, the path specified should start with a slash.
1171    * For URIs that do not follow the generic URI syntax, this method
1172    * sets the scheme-specific part.
1173    *
1174    * @param p_path the path for this URI (may be null)
1175    *
1176    * @throws MalformedURIException if p_path contains invalid
1177    *                                  characters
1178    */
setPath(String p_path)1179   public void setPath(String p_path) throws MalformedURIException
1180   {
1181 
1182     if (p_path == null)
1183     {
1184       m_path = null;
1185       m_queryString = null;
1186       m_fragment = null;
1187     }
1188     else
1189     {
1190       initializePath(p_path);
1191     }
1192   }
1193 
1194   /**
1195    * Append to the end of the path of this URI. If the current path does
1196    * not end in a slash and the path to be appended does not begin with
1197    * a slash, a slash will be appended to the current path before the
1198    * new segment is added. Also, if the current path ends in a slash
1199    * and the new segment begins with a slash, the extra slash will be
1200    * removed before the new segment is appended.
1201    *
1202    * @param p_addToPath the new segment to be added to the current path
1203    *
1204    * @throws MalformedURIException if p_addToPath contains syntax
1205    *                                  errors
1206    */
appendPath(String p_addToPath)1207   public void appendPath(String p_addToPath) throws MalformedURIException
1208   {
1209 
1210     if (p_addToPath == null || p_addToPath.trim().length() == 0)
1211     {
1212       return;
1213     }
1214 
1215     if (!isURIString(p_addToPath))
1216     {
1217       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_PATH_INVALID_CHAR, new Object[]{p_addToPath})); //"Path contains invalid character!");
1218     }
1219 
1220     if (m_path == null || m_path.trim().length() == 0)
1221     {
1222       if (p_addToPath.startsWith("/"))
1223       {
1224         m_path = p_addToPath;
1225       }
1226       else
1227       {
1228         m_path = "/" + p_addToPath;
1229       }
1230     }
1231     else if (m_path.endsWith("/"))
1232     {
1233       if (p_addToPath.startsWith("/"))
1234       {
1235         m_path = m_path.concat(p_addToPath.substring(1));
1236       }
1237       else
1238       {
1239         m_path = m_path.concat(p_addToPath);
1240       }
1241     }
1242     else
1243     {
1244       if (p_addToPath.startsWith("/"))
1245       {
1246         m_path = m_path.concat(p_addToPath);
1247       }
1248       else
1249       {
1250         m_path = m_path.concat("/" + p_addToPath);
1251       }
1252     }
1253   }
1254 
1255   /**
1256    * Set the query string for this URI. A non-null value is valid only
1257    * if this is an URI conforming to the generic URI syntax and
1258    * the path value is not null.
1259    *
1260    * @param p_queryString the query string for this URI
1261    *
1262    * @throws MalformedURIException if p_queryString is not null and this
1263    *                                  URI does not conform to the generic
1264    *                                  URI syntax or if the path is null
1265    */
setQueryString(String p_queryString)1266   public void setQueryString(String p_queryString)
1267           throws MalformedURIException
1268   {
1269 
1270     if (p_queryString == null)
1271     {
1272       m_queryString = null;
1273     }
1274     else if (!isGenericURI())
1275     {
1276       throw new MalformedURIException(
1277         "Query string can only be set for a generic URI!");
1278     }
1279     else if (getPath() == null)
1280     {
1281       throw new MalformedURIException(
1282         "Query string cannot be set when path is null!");
1283     }
1284     else if (!isURIString(p_queryString))
1285     {
1286       throw new MalformedURIException(
1287         "Query string contains invalid character!");
1288     }
1289     else
1290     {
1291       m_queryString = p_queryString;
1292     }
1293   }
1294 
1295   /**
1296    * Set the fragment for this URI. A non-null value is valid only
1297    * if this is a URI conforming to the generic URI syntax and
1298    * the path value is not null.
1299    *
1300    * @param p_fragment the fragment for this URI
1301    *
1302    * @throws MalformedURIException if p_fragment is not null and this
1303    *                                  URI does not conform to the generic
1304    *                                  URI syntax or if the path is null
1305    */
setFragment(String p_fragment)1306   public void setFragment(String p_fragment) throws MalformedURIException
1307   {
1308 
1309     if (p_fragment == null)
1310     {
1311       m_fragment = null;
1312     }
1313     else if (!isGenericURI())
1314     {
1315       throw new MalformedURIException(
1316         XMLMessages.createXMLMessage(XMLErrorResources.ER_FRAG_FOR_GENERIC_URI, null)); //"Fragment can only be set for a generic URI!");
1317     }
1318     else if (getPath() == null)
1319     {
1320       throw new MalformedURIException(
1321         XMLMessages.createXMLMessage(XMLErrorResources.ER_FRAG_WHEN_PATH_NULL, null)); //"Fragment cannot be set when path is null!");
1322     }
1323     else if (!isURIString(p_fragment))
1324     {
1325       throw new MalformedURIException(XMLMessages.createXMLMessage(XMLErrorResources.ER_FRAG_INVALID_CHAR, null)); //"Fragment contains invalid character!");
1326     }
1327     else
1328     {
1329       m_fragment = p_fragment;
1330     }
1331   }
1332 
1333   /**
1334    * Determines if the passed-in Object is equivalent to this URI.
1335    *
1336    * @param p_test the Object to test for equality.
1337    *
1338    * @return true if p_test is a URI with all values equal to this
1339    *         URI, false otherwise
1340    */
equals(Object p_test)1341   public boolean equals(Object p_test)
1342   {
1343 
1344     if (p_test instanceof URI)
1345     {
1346       URI testURI = (URI) p_test;
1347 
1348       if (((m_scheme == null && testURI.m_scheme == null) || (m_scheme != null && testURI.m_scheme != null && m_scheme.equals(
1349               testURI.m_scheme))) && ((m_userinfo == null && testURI.m_userinfo == null) || (m_userinfo != null && testURI.m_userinfo != null && m_userinfo.equals(
1350               testURI.m_userinfo))) && ((m_host == null && testURI.m_host == null) || (m_host != null && testURI.m_host != null && m_host.equals(
1351               testURI.m_host))) && m_port == testURI.m_port && ((m_path == null && testURI.m_path == null) || (m_path != null && testURI.m_path != null && m_path.equals(
1352               testURI.m_path))) && ((m_queryString == null && testURI.m_queryString == null) || (m_queryString != null && testURI.m_queryString != null && m_queryString.equals(
1353               testURI.m_queryString))) && ((m_fragment == null && testURI.m_fragment == null) || (m_fragment != null && testURI.m_fragment != null && m_fragment.equals(
1354               testURI.m_fragment))))
1355       {
1356         return true;
1357       }
1358     }
1359 
1360     return false;
1361   }
1362 
1363   /**
1364    * Get the URI as a string specification. See RFC 2396 Section 5.2.
1365    *
1366    * @return the URI string specification
1367    */
toString()1368   public String toString()
1369   {
1370 
1371     StringBuffer uriSpecString = new StringBuffer();
1372 
1373     if (m_scheme != null)
1374     {
1375       uriSpecString.append(m_scheme);
1376       uriSpecString.append(':');
1377     }
1378 
1379     uriSpecString.append(getSchemeSpecificPart());
1380 
1381     return uriSpecString.toString();
1382   }
1383 
1384   /**
1385    * Get the indicator as to whether this URI uses the "generic URI"
1386    * syntax.
1387    *
1388    * @return true if this URI uses the "generic URI" syntax, false
1389    *         otherwise
1390    */
isGenericURI()1391   public boolean isGenericURI()
1392   {
1393 
1394     // presence of the host (whether valid or empty) means
1395     // double-slashes which means generic uri
1396     return (m_host != null);
1397   }
1398 
1399   /**
1400    * Determine whether a scheme conforms to the rules for a scheme name.
1401    * A scheme is conformant if it starts with an alphanumeric, and
1402    * contains only alphanumerics, '+','-' and '.'.
1403    *
1404    *
1405    * @param p_scheme The sheme name to check
1406    * @return true if the scheme is conformant, false otherwise
1407    */
isConformantSchemeName(String p_scheme)1408   public static boolean isConformantSchemeName(String p_scheme)
1409   {
1410 
1411     if (p_scheme == null || p_scheme.trim().length() == 0)
1412     {
1413       return false;
1414     }
1415 
1416     if (!isAlpha(p_scheme.charAt(0)))
1417     {
1418       return false;
1419     }
1420 
1421     char testChar;
1422 
1423     for (int i = 1; i < p_scheme.length(); i++)
1424     {
1425       testChar = p_scheme.charAt(i);
1426 
1427       if (!isAlphanum(testChar) && SCHEME_CHARACTERS.indexOf(testChar) == -1)
1428       {
1429         return false;
1430       }
1431     }
1432 
1433     return true;
1434   }
1435 
1436   /**
1437    * Determine whether a string is syntactically capable of representing
1438    * a valid IPv4 address or the domain name of a network host. A valid
1439    * IPv4 address consists of four decimal digit groups separated by a
1440    * '.'. A hostname consists of domain labels (each of which must
1441    * begin and end with an alphanumeric but may contain '-') separated
1442    * & by a '.'. See RFC 2396 Section 3.2.2.
1443    *
1444    *
1445    * @param p_address The address string to check
1446    * @return true if the string is a syntactically valid IPv4 address
1447    *              or hostname
1448    */
isWellFormedAddress(String p_address)1449   public static boolean isWellFormedAddress(String p_address)
1450   {
1451 
1452     if (p_address == null)
1453     {
1454       return false;
1455     }
1456 
1457     String address = p_address.trim();
1458     int addrLength = address.length();
1459 
1460     if (addrLength == 0 || addrLength > 255)
1461     {
1462       return false;
1463     }
1464 
1465     if (address.startsWith(".") || address.startsWith("-"))
1466     {
1467       return false;
1468     }
1469 
1470     // rightmost domain label starting with digit indicates IP address
1471     // since top level domain label can only start with an alpha
1472     // see RFC 2396 Section 3.2.2
1473     int index = address.lastIndexOf('.');
1474 
1475     if (address.endsWith("."))
1476     {
1477       index = address.substring(0, index).lastIndexOf('.');
1478     }
1479 
1480     if (index + 1 < addrLength && isDigit(p_address.charAt(index + 1)))
1481     {
1482       char testChar;
1483       int numDots = 0;
1484 
1485       // make sure that 1) we see only digits and dot separators, 2) that
1486       // any dot separator is preceded and followed by a digit and
1487       // 3) that we find 3 dots
1488       for (int i = 0; i < addrLength; i++)
1489       {
1490         testChar = address.charAt(i);
1491 
1492         if (testChar == '.')
1493         {
1494           if (!isDigit(address.charAt(i - 1))
1495                   || (i + 1 < addrLength &&!isDigit(address.charAt(i + 1))))
1496           {
1497             return false;
1498           }
1499 
1500           numDots++;
1501         }
1502         else if (!isDigit(testChar))
1503         {
1504           return false;
1505         }
1506       }
1507 
1508       if (numDots != 3)
1509       {
1510         return false;
1511       }
1512     }
1513     else
1514     {
1515 
1516       // domain labels can contain alphanumerics and '-"
1517       // but must start and end with an alphanumeric
1518       char testChar;
1519 
1520       for (int i = 0; i < addrLength; i++)
1521       {
1522         testChar = address.charAt(i);
1523 
1524         if (testChar == '.')
1525         {
1526           if (!isAlphanum(address.charAt(i - 1)))
1527           {
1528             return false;
1529           }
1530 
1531           if (i + 1 < addrLength &&!isAlphanum(address.charAt(i + 1)))
1532           {
1533             return false;
1534           }
1535         }
1536         else if (!isAlphanum(testChar) && testChar != '-')
1537         {
1538           return false;
1539         }
1540       }
1541     }
1542 
1543     return true;
1544   }
1545 
1546   /**
1547    * Determine whether a char is a digit.
1548    *
1549    *
1550    * @param p_char the character to check
1551    * @return true if the char is betweeen '0' and '9', false otherwise
1552    */
isDigit(char p_char)1553   private static boolean isDigit(char p_char)
1554   {
1555     return p_char >= '0' && p_char <= '9';
1556   }
1557 
1558   /**
1559    * Determine whether a character is a hexadecimal character.
1560    *
1561    *
1562    * @param p_char the character to check
1563    * @return true if the char is betweeen '0' and '9', 'a' and 'f'
1564    *         or 'A' and 'F', false otherwise
1565    */
isHex(char p_char)1566   private static boolean isHex(char p_char)
1567   {
1568     return (isDigit(p_char) || (p_char >= 'a' && p_char <= 'f')
1569             || (p_char >= 'A' && p_char <= 'F'));
1570   }
1571 
1572   /**
1573    * Determine whether a char is an alphabetic character: a-z or A-Z
1574    *
1575    *
1576    * @param p_char the character to check
1577    * @return true if the char is alphabetic, false otherwise
1578    */
isAlpha(char p_char)1579   private static boolean isAlpha(char p_char)
1580   {
1581     return ((p_char >= 'a' && p_char <= 'z')
1582             || (p_char >= 'A' && p_char <= 'Z'));
1583   }
1584 
1585   /**
1586    * Determine whether a char is an alphanumeric: 0-9, a-z or A-Z
1587    *
1588    *
1589    * @param p_char the character to check
1590    * @return true if the char is alphanumeric, false otherwise
1591    */
isAlphanum(char p_char)1592   private static boolean isAlphanum(char p_char)
1593   {
1594     return (isAlpha(p_char) || isDigit(p_char));
1595   }
1596 
1597   /**
1598    * Determine whether a character is a reserved character:
1599    * ';', '/', '?', ':', '@', '&', '=', '+', '$' or ','
1600    *
1601    *
1602    * @param p_char the character to check
1603    * @return true if the string contains any reserved characters
1604    */
isReservedCharacter(char p_char)1605   private static boolean isReservedCharacter(char p_char)
1606   {
1607     return RESERVED_CHARACTERS.indexOf(p_char) != -1;
1608   }
1609 
1610   /**
1611    * Determine whether a char is an unreserved character.
1612    *
1613    *
1614    * @param p_char the character to check
1615    * @return true if the char is unreserved, false otherwise
1616    */
isUnreservedCharacter(char p_char)1617   private static boolean isUnreservedCharacter(char p_char)
1618   {
1619     return (isAlphanum(p_char) || MARK_CHARACTERS.indexOf(p_char) != -1);
1620   }
1621 
1622   /**
1623    * Determine whether a given string contains only URI characters (also
1624    * called "uric" in RFC 2396). uric consist of all reserved
1625    * characters, unreserved characters and escaped characters.
1626    *
1627    *
1628    * @param p_uric URI string
1629    * @return true if the string is comprised of uric, false otherwise
1630    */
isURIString(String p_uric)1631   private static boolean isURIString(String p_uric)
1632   {
1633 
1634     if (p_uric == null)
1635     {
1636       return false;
1637     }
1638 
1639     int end = p_uric.length();
1640     char testChar = '\0';
1641 
1642     for (int i = 0; i < end; i++)
1643     {
1644       testChar = p_uric.charAt(i);
1645 
1646       if (testChar == '%')
1647       {
1648         if (i + 2 >= end ||!isHex(p_uric.charAt(i + 1))
1649                 ||!isHex(p_uric.charAt(i + 2)))
1650         {
1651           return false;
1652         }
1653         else
1654         {
1655           i += 2;
1656 
1657           continue;
1658         }
1659       }
1660 
1661       if (isReservedCharacter(testChar) || isUnreservedCharacter(testChar))
1662       {
1663         continue;
1664       }
1665       else
1666       {
1667         return false;
1668       }
1669     }
1670 
1671     return true;
1672   }
1673 }
1674