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
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 */
69 public ParameterParser() {
70 super();
71 }
72
73
74 /*** Are there any characters left to parse? */
75 private boolean hasChar() {
76 return this.pos < this.len;
77 }
78
79
80 /*** A helper method to process the parsed token. */
81 private String getToken(boolean quoted) {
82
83 while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) {
84 i1++;
85 }
86
87 while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) {
88 i2--;
89 }
90
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? */
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. */
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. */
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 */
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 */
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 */
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++;
224 paramValue = parseQuotedToken(new char[] {separator});
225 }
226 if (hasChar() && (chars[pos] == separator)) {
227 pos++;
228 }
229 if (paramName != null && !(paramName.equals("") && paramValue == null)) {
230 params.add(new NameValuePair(paramName, paramValue));
231 }
232 }
233 return params;
234 }
235 }