PageRenderTime 84ms CodeModel.GetById 25ms app.highlight 41ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/jre-1.6.0/src/com/sun/org/apache/xml/internal/utils/URI.java

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