1 /*
   2 Copyright (c) 2001, 2002 Thai Open Source Software Center Ltd
   3 All rights reserved.
   4 
   5 Redistribution and use in source and binary forms, with or without
   6 modification, are permitted provided that the following conditions are
   7 met:
   8 
   9     Redistributions of source code must retain the above copyright
  10     notice, this list of conditions and the following disclaimer.
  11 
  12     Redistributions in binary form must reproduce the above copyright
  13     notice, this list of conditions and the following disclaimer in
  14     the documentation and/or other materials provided with the
  15     distribution.
  16 
  17     Neither the name of the Thai Open Source Software Center Ltd nor
  18     the names of its contributors may be used to endorse or promote
  19     products derived from this software without specific prior written
  20     permission.
  21 
  22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
  26 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  27 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  28 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  30 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  31 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33 */
  34 // @@3RD PARTY CODE@@
  35 
  36 package com.sun.xml.internal.xsom.impl.util;
  37 
  38 import java.io.IOException;
  39 import java.io.UnsupportedEncodingException;
  40 import java.net.URL;
  41 
  42 public class Uri {
  43   private static String utf8 = "UTF-8";
  44 
  45   public static boolean isValid(String s) {
  46     return isValidPercent(s) && isValidFragment(s) && isValidScheme(s);
  47   }
  48 
  49   private static final String HEX_DIGITS = "0123456789abcdef";
  50 
  51   public static String escapeDisallowedChars(String s) {
  52     StringBuffer buf = null;
  53     int len = s.length();
  54     int done = 0;
  55     for (;;) {
  56       int i = done;
  57       for (;;) {
  58         if (i == len) {
  59           if (done == 0)
  60             return s;
  61           break;
  62         }
  63         if (isExcluded(s.charAt(i)))
  64           break;
  65         i++;
  66       }
  67       if (buf == null)
  68         buf = new StringBuffer();
  69       if (i > done) {
  70         buf.append(s.substring(done, i));
  71         done = i;
  72       }
  73       if (i == len)
  74         break;
  75       for (i++; i < len && isExcluded(s.charAt(i)); i++)
  76         ;
  77       String tem = s.substring(done, i);
  78       byte[] bytes;
  79       try {
  80         bytes = tem.getBytes(utf8);
  81       }
  82       catch (UnsupportedEncodingException e) {
  83         utf8 = "UTF8";
  84         try {
  85           bytes = tem.getBytes(utf8);
  86         }
  87         catch (UnsupportedEncodingException e2) {
  88           // Give up
  89           return s;
  90         }
  91       }
  92       for (int j = 0; j < bytes.length; j++) {
  93         buf.append('%');
  94         buf.append(HEX_DIGITS.charAt((bytes[j] & 0xFF) >> 4));
  95         buf.append(HEX_DIGITS.charAt(bytes[j] & 0xF));
  96       }
  97       done = i;
  98     }
  99     return buf.toString();
 100   }
 101 
 102   private static String excluded = "<>\"{}|\\^`";
 103 
 104   private static boolean isExcluded(char c) {
 105     return c <= 0x20 || c >= 0x7F || excluded.indexOf(c) >= 0;
 106   }
 107 
 108   private static boolean isAlpha(char c) {
 109     return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
 110   }
 111 
 112   private static boolean isHexDigit(char c) {
 113     return ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') || isDigit(c);
 114   }
 115 
 116   private static boolean isDigit(char c) {
 117     return '0' <= c && c <= '9';
 118   }
 119 
 120   private static boolean isSchemeChar(char c) {
 121     return isAlpha(c) || isDigit(c) || c == '+' || c == '-' || c =='.';
 122   }
 123 
 124   private static boolean isValidPercent(String s) {
 125     int len = s.length();
 126     for (int i = 0; i < len; i++)
 127       if (s.charAt(i) == '%') {
 128         if (i + 2 >= len)
 129           return false;
 130         else if (!isHexDigit(s.charAt(i + 1))
 131              || !isHexDigit(s.charAt(i + 2)))
 132           return false;
 133       }
 134     return true;
 135   }
 136 
 137   private static boolean isValidFragment(String s) {
 138     int i = s.indexOf('#');
 139     return i < 0 || s.indexOf('#', i + 1) < 0;
 140   }
 141 
 142   private static boolean isValidScheme(String s) {
 143     if (!isAbsolute(s))
 144       return true;
 145     int i = s.indexOf(':');
 146     if (i == 0
 147     || i + 1 == s.length()
 148     || !isAlpha(s.charAt(0)))
 149       return false;
 150     while (--i > 0)
 151       if (!isSchemeChar(s.charAt(i)))
 152     return false;
 153     return true;
 154   }
 155 
 156     public static String resolve(String baseUri, String uriReference) throws IOException {
 157         if (isAbsolute(uriReference))
 158             return uriReference;
 159 
 160         if(baseUri==null)
 161             throw new IOException("Unable to resolve relative URI "+uriReference+" without a base URI");
 162 
 163         if(!isAbsolute(baseUri))
 164             throw new IOException("Unable to resolve relative URI "+uriReference+" because base URI is not absolute: "+baseUri);
 165 
 166         return new URL(new URL(baseUri), uriReference).toString();
 167     }
 168 
 169     public static boolean hasFragmentId(String uri) {
 170     return uri.indexOf('#') >= 0;
 171   }
 172 
 173   public static boolean isAbsolute(String uri) {
 174     int i = uri.indexOf(':');
 175     if (i < 0)
 176       return false;
 177     while (--i >= 0) {
 178       switch (uri.charAt(i)) {
 179       case '#':
 180       case '/':
 181       case '?':
 182     return false;
 183       }
 184     }
 185     return true;
 186   }
 187 }