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