| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.datatypes; |
| |
| import java.io.UnsupportedEncodingException; |
| |
| |
| /** |
| * This class contains method to deal with the <uri-specification> datatype from XSL-FO. |
| */ |
| public final class URISpecification { |
| |
| private URISpecification() { |
| } |
| |
| /** |
| * Get the URL string from a wrapped URL. |
| * |
| * @param href the input wrapped URL |
| * @return the raw URL |
| */ |
| public static String getURL(String href) { |
| /* |
| * According to section 5.11 a <uri-specification> is: |
| * "url(" + URI + ")" |
| * according to 7.28.7 a <uri-specification> is: |
| * URI |
| * So handle both. |
| */ |
| href = href.trim(); |
| if (href.startsWith("url(") && (href.indexOf(")") != -1)) { |
| href = href.substring(4, href.lastIndexOf(")")).trim(); |
| if (href.startsWith("'") && href.endsWith("'")) { |
| href = href.substring(1, href.length() - 1); |
| } else if (href.startsWith("\"") && href.endsWith("\"")) { |
| href = href.substring(1, href.length() - 1); |
| } |
| } else { |
| // warn |
| } |
| return href; |
| } |
| |
| private static final String PUNCT = ",;:$&+="; |
| private static final String RESERVED = PUNCT + "?/[]@"; |
| |
| /* not used |
| private static boolean isValidURIChar(char ch) { |
| return true; |
| } |
| */ |
| |
| private static boolean isDigit(char ch) { |
| return (ch >= '0' && ch <= '9'); |
| } |
| |
| private static boolean isAlpha(char ch) { |
| return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); |
| } |
| |
| private static boolean isHexDigit(char ch) { |
| return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'); |
| } |
| |
| private static boolean isReserved(char ch) { |
| if (RESERVED.indexOf(ch) >= 0) { |
| return true; |
| } else if ('#' == ch) { |
| //# is not a reserved character but is used for the fragment |
| return true; |
| } |
| return false; |
| } |
| |
| private static boolean isUnreserved(char ch) { |
| if (isDigit(ch) || isAlpha(ch)) { |
| return true; |
| } else if ("_-!.~\'()*".indexOf(ch) >= 0) { |
| //remaining unreserved characters |
| return true; |
| } |
| return false; |
| } |
| |
| private static final char[] HEX_DIGITS = { |
| '0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' |
| }; |
| |
| private static void appendEscape(StringBuffer sb, byte b) { |
| sb.append('%').append(HEX_DIGITS[(b >> 4) & 0x0f]).append(HEX_DIGITS[(b >> 0) & 0x0f]); |
| } |
| |
| /** |
| * Escapes any illegal URI character in a given URI, for example, it escapes a space to "%20". |
| * Note: This method does not "parse" the URI and therefore does not treat the individual |
| * components (user-info, path, query etc.) individually. |
| * @param uri the URI to inspect |
| * @return the escaped URI |
| */ |
| public static String escapeURI(String uri) { |
| uri = getURL(uri); |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0, c = uri.length(); i < c; i++) { |
| char ch = uri.charAt(i); |
| if (ch == '%') { |
| if (i < c - 3 && isHexDigit(uri.charAt(i + 1)) && isHexDigit(uri.charAt(i + 2))) { |
| sb.append(ch); |
| continue; |
| } |
| } |
| if (isReserved(ch) || isUnreserved(ch)) { |
| //Note: this may not be accurate for some very special cases. |
| sb.append(ch); |
| } else { |
| try { |
| byte[] utf8 = Character.toString(ch).getBytes("UTF-8"); |
| for (byte anUtf8 : utf8) { |
| appendEscape(sb, anUtf8); |
| } |
| } catch (UnsupportedEncodingException e) { |
| throw new Error("Incompatible JVM. UTF-8 not supported."); |
| } |
| } |
| } |
| return sb.toString(); |
| } |
| |
| } |