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 boolean charEscaped = false;
146 while (hasChar()) {
147 ch = chars[pos];
148 if (!quoted && isOneOf(ch, terminators)) {
149 break;
150 }
151 if (!charEscaped && ch == '"') {
152 quoted = !quoted;
153 }
154 charEscaped = (!charEscaped && ch == '//');
155 i2++;
156 pos++;
157
158 }
159 return getToken(true);
160 }
161
162 /***
163 * Extracts a list of {@link NameValuePair}s from the given string.
164 *
165 * @param str the string that contains a sequence of name/value pairs
166 * @return a list of {@link NameValuePair}s
167 *
168 */
169 public List parse(final String str, char separator) {
170
171 if (str == null) {
172 return new ArrayList();
173 }
174 return parse(str.toCharArray(), separator);
175 }
176
177 /***
178 * Extracts a list of {@link NameValuePair}s from the given array of
179 * characters.
180 *
181 * @param chars the array of characters that contains a sequence of
182 * name/value pairs
183 *
184 * @return a list of {@link NameValuePair}s
185 */
186 public List parse(final char[] chars, char separator) {
187
188 if (chars == null) {
189 return new ArrayList();
190 }
191 return parse(chars, 0, chars.length, separator);
192 }
193
194
195 /***
196 * Extracts a list of {@link NameValuePair}s from the given array of
197 * characters.
198 *
199 * @param chars the array of characters that contains a sequence of
200 * name/value pairs
201 * @param offset - the initial offset.
202 * @param length - the length.
203 *
204 * @return a list of {@link NameValuePair}s
205 */
206 public List parse(final char[] chars, int offset, int length, char separator) {
207
208 if (chars == null) {
209 return new ArrayList();
210 }
211 List params = new ArrayList();
212 this.chars = chars;
213 this.pos = offset;
214 this.len = length;
215
216 String paramName = null;
217 String paramValue = null;
218 while (hasChar()) {
219 paramName = parseToken(new char[] {'=', separator});
220 paramValue = null;
221 if (hasChar() && (chars[pos] == '=')) {
222 pos++;
223 paramValue = parseQuotedToken(new char[] {separator});
224 }
225 if (hasChar() && (chars[pos] == separator)) {
226 pos++;
227 }
228 if (paramName != null && !(paramName.equals("") && paramValue == null)) {
229 params.add(new NameValuePair(paramName, paramValue));
230 }
231 }
232 return params;
233 }
234 }