1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.sun.org.apache.xml.internal.resolver.helpers; 19 20 /** 21 * Static methods for dealing with public identifiers. 22 * 23 * <p>This class defines a set of static methods that can be called 24 * to handle public identifiers.</p> 25 * 26 * @author Norman Walsh 27 * <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a> 28 * 29 */ 30 public abstract class PublicId { 31 32 protected PublicId() {} 33 34 /** 35 * Normalize a public identifier. 36 * 37 * <p>Public identifiers must be normalized according to the following 38 * rules before comparisons between them can be made:</p> 39 * 40 * <ul> 41 * <li>Whitespace characters are normalized to spaces (e.g., line feeds, 42 * tabs, etc. become spaces).</li> 43 * <li>Leading and trailing whitespace is removed.</li> 44 * <li>Multiple internal whitespaces are normalized to a single 45 * space.</li> 46 * </ul> 47 * 48 * <p>This method is declared static so that other classes 49 * can use it directly.</p> 50 * 51 * @param publicId The unnormalized public identifier. 52 * 53 * @return The normalized identifier. 54 */ 55 public static String normalize(String publicId) { 56 String normal = publicId.replace('\t', ' '); 57 normal = normal.replace('\r', ' '); 58 normal = normal.replace('\n', ' '); 59 normal = normal.trim(); 60 61 int pos; 62 63 while ((pos = normal.indexOf(" ")) >= 0) { 64 normal = normal.substring(0, pos) + normal.substring(pos+1); 65 } 66 return normal; 67 } 68 69 /** 70 * Encode a public identifier as a "publicid" URN. 71 * 72 * <p>This method is declared static so that other classes 73 * can use it directly.</p> 74 * 75 * @param publicId The unnormalized public identifier. 76 * 77 * @return The normalized identifier. 78 */ 79 public static String encodeURN(String publicId) { 80 String urn = PublicId.normalize(publicId); 81 82 urn = PublicId.stringReplace(urn, "%", "%25"); 83 urn = PublicId.stringReplace(urn, ";", "%3B"); 84 urn = PublicId.stringReplace(urn, "'", "%27"); 85 urn = PublicId.stringReplace(urn, "?", "%3F"); 86 urn = PublicId.stringReplace(urn, "#", "%23"); 87 urn = PublicId.stringReplace(urn, "+", "%2B"); 88 urn = PublicId.stringReplace(urn, " ", "+"); 89 urn = PublicId.stringReplace(urn, "::", ";"); 90 urn = PublicId.stringReplace(urn, ":", "%3A"); 91 urn = PublicId.stringReplace(urn, "//", ":"); 92 urn = PublicId.stringReplace(urn, "/", "%2F"); 93 94 StringBuilder buffer = new StringBuilder(13 + urn.length()); 95 buffer.append("urn:publicid:"); 96 buffer.append(urn); 97 return buffer.toString(); 98 } 99 100 /** 101 * Decode a "publicid" URN into a public identifier. 102 * 103 * <p>This method is declared static so that other classes 104 * can use it directly.</p> 105 * 106 * @param urn The urn:publicid: URN 107 * 108 * @return The normalized identifier. 109 */ 110 public static String decodeURN(String urn) { 111 String publicId; 112 if (urn.startsWith("urn:publicid:")) { 113 publicId = urn.substring(13); 114 } 115 else { 116 return urn; 117 } 118 119 final boolean hasEscape = (publicId.indexOf('%') >= 0); 120 if (hasEscape) { 121 publicId = PublicId.stringReplace(publicId, "%2F", "/"); 122 } 123 publicId = PublicId.stringReplace(publicId, ":", "//"); 124 if (hasEscape) { 125 publicId = PublicId.stringReplace(publicId, "%3A", ":"); 126 } 127 publicId = PublicId.stringReplace(publicId, ";", "::"); 128 publicId = PublicId.stringReplace(publicId, "+", " "); 129 if (hasEscape) { 130 publicId = PublicId.stringReplace(publicId, "%2B", "+"); 131 publicId = PublicId.stringReplace(publicId, "%23", "#"); 132 publicId = PublicId.stringReplace(publicId, "%3F", "?"); 133 publicId = PublicId.stringReplace(publicId, "%27", "'"); 134 publicId = PublicId.stringReplace(publicId, "%3B", ";"); 135 publicId = PublicId.stringReplace(publicId, "%25", "%"); 136 } 137 138 return publicId; 139 } 140 141 /** 142 * Replace one string with another. 143 */ 144 private static String stringReplace(String str, 145 String oldStr, 146 String newStr) { 147 int pos = str.indexOf(oldStr); 148 if (pos >= 0) { 149 final StringBuilder buffer = new StringBuilder(); 150 final int oldStrLength = oldStr.length(); 151 int start = 0; 152 do { 153 for (int i = start; i < pos; ++i) { 154 buffer.append(str.charAt(i)); 155 } 156 buffer.append(newStr); 157 start = pos + oldStrLength; 158 pos = str.indexOf(oldStr, start); 159 } 160 while (pos >= 0); 161 final int strLength = str.length(); 162 for (int i = start; i < strLength; ++i) { 163 buffer.append(str.charAt(i)); 164 } 165 return buffer.toString(); 166 } 167 return str; 168 } 169 }