1 /* 2 * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/util/ParameterParser.java,v 1.5 2004/05/13 04:01:22 mbecke Exp $ 3 * $Revision: 480424 $ 4 * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ 5 * 6 * ==================================================================== 7 * 8 * Licensed to the Apache Software Foundation (ASF) under one or more 9 * contributor license agreements. See the NOTICE file distributed with 10 * this work for additional information regarding copyright ownership. 11 * The ASF licenses this file to You under the Apache License, Version 2.0 12 * (the "License"); you may not use this file except in compliance with 13 * the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * ==================================================================== 23 * 24 * This software consists of voluntary contributions made by many 25 * individuals on behalf of the Apache Software Foundation. For more 26 * information on the Apache Software Foundation, please see 27 * <http://www.apache.org/>. 28 * 29 */ 30 31 package org.apache.commons.httpclient.util; 32 import java.util.ArrayList; 33 import java.util.List; 34 35 import org.apache.commons.httpclient.NameValuePair; 36 37 /** 38 * A simple parser intended to parse sequences of name/value pairs. 39 * Parameter values are exptected to be enclosed in quotes if they 40 * contain unsafe characters, such as '=' characters or separators. 41 * Parameter values are optional and can be omitted. 42 * 43 * <p> 44 * <code>param1 = value; param2 = "anything goes; really"; param3</code> 45 * </p> 46 * 47 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> 48 * 49 * @since 3.0 50 */ 51 public class ParameterParser { 52 53 /** String to be parsed */ 54 private char[] chars = null; 55 56 /** Current position in the string */ 57 private int pos = 0; 58 59 /** Maximum position in the string */ 60 private int len = 0; 61 62 /** Start of a token */ 63 private int i1 = 0; 64 65 /** End of a token */ 66 private int i2 = 0; 67 68 /** Default ParameterParser constructor */ ParameterParser()69 public ParameterParser() { 70 super(); 71 } 72 73 74 /** Are there any characters left to parse? */ hasChar()75 private boolean hasChar() { 76 return this.pos < this.len; 77 } 78 79 80 /** A helper method to process the parsed token. */ getToken(boolean quoted)81 private String getToken(boolean quoted) { 82 // Trim leading white spaces 83 while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) { 84 i1++; 85 } 86 // Trim trailing white spaces 87 while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) { 88 i2--; 89 } 90 // Strip away quotes if necessary 91 if (quoted) { 92 if (((i2 - i1) >= 2) 93 && (chars[i1] == '"') 94 && (chars[i2 - 1] == '"')) { 95 i1++; 96 i2--; 97 } 98 } 99 String result = null; 100 if (i2 >= i1) { 101 result = new String(chars, i1, i2 - i1); 102 } 103 return result; 104 } 105 106 107 /** Is given character present in the array of characters? */ isOneOf(char ch, char[] charray)108 private boolean isOneOf(char ch, char[] charray) { 109 boolean result = false; 110 for (int i = 0; i < charray.length; i++) { 111 if (ch == charray[i]) { 112 result = true; 113 break; 114 } 115 } 116 return result; 117 } 118 119 120 /** Parse out a token until any of the given terminators 121 * is encountered. */ parseToken(final char[] terminators)122 private String parseToken(final char[] terminators) { 123 char ch; 124 i1 = pos; 125 i2 = pos; 126 while (hasChar()) { 127 ch = chars[pos]; 128 if (isOneOf(ch, terminators)) { 129 break; 130 } 131 i2++; 132 pos++; 133 } 134 return getToken(false); 135 } 136 137 138 /** Parse out a token until any of the given terminators 139 * is encountered. Special characters in quoted tokens 140 * are escaped. */ parseQuotedToken(final char[] terminators)141 private String parseQuotedToken(final char[] terminators) { 142 char ch; 143 i1 = pos; 144 i2 = pos; 145 boolean quoted = false; 146 boolean charEscaped = false; 147 while (hasChar()) { 148 ch = chars[pos]; 149 if (!quoted && isOneOf(ch, terminators)) { 150 break; 151 } 152 if (!charEscaped && ch == '"') { 153 quoted = !quoted; 154 } 155 charEscaped = (!charEscaped && ch == '\\'); 156 i2++; 157 pos++; 158 159 } 160 return getToken(true); 161 } 162 163 /** 164 * Extracts a list of {@link NameValuePair}s from the given string. 165 * 166 * @param str the string that contains a sequence of name/value pairs 167 * @return a list of {@link NameValuePair}s 168 * 169 */ parse(final String str, char separator)170 public List parse(final String str, char separator) { 171 172 if (str == null) { 173 return new ArrayList(); 174 } 175 return parse(str.toCharArray(), separator); 176 } 177 178 /** 179 * Extracts a list of {@link NameValuePair}s from the given array of 180 * characters. 181 * 182 * @param chars the array of characters that contains a sequence of 183 * name/value pairs 184 * 185 * @return a list of {@link NameValuePair}s 186 */ parse(final char[] chars, char separator)187 public List parse(final char[] chars, char separator) { 188 189 if (chars == null) { 190 return new ArrayList(); 191 } 192 return parse(chars, 0, chars.length, separator); 193 } 194 195 196 /** 197 * Extracts a list of {@link NameValuePair}s from the given array of 198 * characters. 199 * 200 * @param chars the array of characters that contains a sequence of 201 * name/value pairs 202 * @param offset - the initial offset. 203 * @param length - the length. 204 * 205 * @return a list of {@link NameValuePair}s 206 */ parse(final char[] chars, int offset, int length, char separator)207 public List parse(final char[] chars, int offset, int length, char separator) { 208 209 if (chars == null) { 210 return new ArrayList(); 211 } 212 List params = new ArrayList(); 213 this.chars = chars; 214 this.pos = offset; 215 this.len = length; 216 217 String paramName = null; 218 String paramValue = null; 219 while (hasChar()) { 220 paramName = parseToken(new char[] {'=', separator}); 221 paramValue = null; 222 if (hasChar() && (chars[pos] == '=')) { 223 pos++; // skip '=' 224 paramValue = parseQuotedToken(new char[] {separator}); 225 } 226 if (hasChar() && (chars[pos] == separator)) { 227 pos++; // skip separator 228 } 229 if (paramName != null && !(paramName.equals("") && paramValue == null)) { 230 params.add(new NameValuePair(paramName, paramValue)); 231 } 232 } 233 return params; 234 } 235 } 236