1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient.util;
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import org.apache.commons.httpclient.NameValuePair;
35
36 /***
37 * A simple parser intended to parse sequences of name/value pairs.
38 * Parameter values are exptected to be enclosed in quotes if they
39 * contain unsafe characters, such as '=' characters or separators.
40 * Parameter values are optional and can be omitted.
41 *
42 * <p>
43 * <code>param1 = value; param2 = "anything goes; really"; param3</code>
44 * </p>
45 *
46 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
47 *
48 * @since 3.0
49 */
50 public class ParameterParser {
51
52 /*** String to be parsed */
53 private char[] chars = null;
54
55 /*** Current position in the string */
56 private int pos = 0;
57
58 /*** Maximum position in the string */
59 private int len = 0;
60
61 /*** Start of a token */
62 private int i1 = 0;
63
64 /*** End of a token */
65 private int i2 = 0;
66
67 /*** Default ParameterParser constructor */
68 public ParameterParser() {
69 super();
70 }
71
72
73 /*** Are there any characters left to parse? */
74 private boolean hasChar() {
75 return this.pos < this.len;
76 }
77
78
79 /*** A helper method to process the parsed token. */
80 private String getToken(boolean quoted) {
81
82 while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) {
83 i1++;
84 }
85
86 while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) {
87 i2--;
88 }
89
90 if (quoted) {
91 if (((i2 - i1) >= 2)
92 && (chars[i1] == '"')
93 && (chars[i2 - 1] == '"')) {
94 i1++;
95 i2--;
96 }
97 }
98 String result = null;
99 if (i2 > i1) {
100 result = new String(chars, i1, i2 - i1);
101 }
102 return result;
103 }
104
105
106 /*** Is given character present in the array of characters? */
107 private boolean isOneOf(char ch, char[] charray) {
108 boolean result = false;
109 for (int i = 0; i < charray.length; i++) {
110 if (ch == charray[i]) {
111 result = true;
112 break;
113 }
114 }
115 return result;
116 }
117
118
119 /*** Parse out a token until any of the given terminators
120 * is encountered. */
121 private String parseToken(final char[] terminators) {
122 char ch;
123 i1 = pos;
124 i2 = pos;
125 while (hasChar()) {
126 ch = chars[pos];
127 if (isOneOf(ch, terminators)) {
128 break;
129 }
130 i2++;
131 pos++;
132 }
133 return getToken(false);
134 }
135
136
137 /*** Parse out a token until any of the given terminators
138 * is encountered. Special characters in quoted tokens
139 * are escaped. */
140 private String parseQuotedToken(final char[] terminators) {
141 char ch;
142 i1 = pos;
143 i2 = pos;
144 boolean quoted = false;
145 while (hasChar()) {
146 ch = chars[pos];
147 if (!quoted && isOneOf(ch, terminators)) {
148 break;
149 }
150 if (ch == '"') {
151 quoted = !quoted;
152 }
153 i2++;
154 pos++;
155 }
156 return getToken(true);
157 }
158
159 /***
160 * Extracts a list of {@link NameValuePair}s from the given string.
161 *
162 * @param str the string that contains a sequence of name/value pairs
163 * @return a list of {@link NameValuePair}s
164 *
165 */
166 public List parse(final String str, char separator) {
167
168 if (str == null) {
169 return new ArrayList();
170 }
171 return parse(str.toCharArray(), separator);
172 }
173
174 /***
175 * Extracts a list of {@link NameValuePair}s from the given array of
176 * characters.
177 *
178 * @param chars the array of characters that contains a sequence of
179 * name/value pairs
180 *
181 * @return a list of {@link NameValuePair}s
182 */
183 public List parse(final char[] chars, char separator) {
184
185 if (chars == null) {
186 return new ArrayList();
187 }
188 return parse(chars, 0, chars.length, separator);
189 }
190
191
192 /***
193 * Extracts a list of {@link NameValuePair}s from the given array of
194 * characters.
195 *
196 * @param chars the array of characters that contains a sequence of
197 * name/value pairs
198 * @param offset - the initial offset.
199 * @param length - the length.
200 *
201 * @return a list of {@link NameValuePair}s
202 */
203 public List parse(final char[] chars, int offset, int length, char separator) {
204
205 if (chars == null) {
206 return new ArrayList();
207 }
208 List params = new ArrayList();
209 this.chars = chars;
210 this.pos = offset;
211 this.len = length;
212
213 String paramName = null;
214 String paramValue = null;
215 while (hasChar()) {
216 paramName = parseToken(new char[] {'=', separator});
217 paramValue = null;
218 if (hasChar() && (chars[pos] == '=')) {
219 pos++;
220 paramValue = parseQuotedToken(new char[] {separator});
221 }
222 if (hasChar() && (chars[pos] == separator)) {
223 pos++;
224 }
225 if ((paramName != null) && (paramName.length() > 0)) {
226 params.add(new NameValuePair(paramName, paramValue));
227 }
228 }
229 return params;
230 }
231 }