1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util;
20
21 import java.io.IOException;
22 import java.util.Arrays;
23 import java.util.NoSuchElementException;
24 import java.util.StringTokenizer;
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public class QuotedStringTokenizer
39 extends StringTokenizer
40 {
41 private final static String __delim="\t\n\r";
42 private String _string;
43 private String _delim = __delim;
44 private boolean _returnQuotes=false;
45 private boolean _returnDelimiters=false;
46 private StringBuffer _token;
47 private boolean _hasToken=false;
48 private int _i=0;
49 private int _lastStart=0;
50 private boolean _double=true;
51 private boolean _single=true;
52
53
54 public QuotedStringTokenizer(String str,
55 String delim,
56 boolean returnDelimiters,
57 boolean returnQuotes)
58 {
59 super("");
60 _string=str;
61 if (delim!=null)
62 _delim=delim;
63 _returnDelimiters=returnDelimiters;
64 _returnQuotes=returnQuotes;
65
66 if (_delim.indexOf('\'')>=0 ||
67 _delim.indexOf('"')>=0)
68 throw new Error("Can't use quotes as delimiters: "+_delim);
69
70 _token=new StringBuffer(_string.length()>1024?512:_string.length()/2);
71 }
72
73
74 public QuotedStringTokenizer(String str,
75 String delim,
76 boolean returnDelimiters)
77 {
78 this(str,delim,returnDelimiters,false);
79 }
80
81
82 public QuotedStringTokenizer(String str,
83 String delim)
84 {
85 this(str,delim,false,false);
86 }
87
88
89 public QuotedStringTokenizer(String str)
90 {
91 this(str,null,false,false);
92 }
93
94
95 @Override
96 public boolean hasMoreTokens()
97 {
98
99 if (_hasToken)
100 return true;
101
102 _lastStart=_i;
103
104 int state=0;
105 boolean escape=false;
106 while (_i<_string.length())
107 {
108 char c=_string.charAt(_i++);
109
110 switch (state)
111 {
112 case 0:
113 if(_delim.indexOf(c)>=0)
114 {
115 if (_returnDelimiters)
116 {
117 _token.append(c);
118 return _hasToken=true;
119 }
120 }
121 else if (c=='\'' && _single)
122 {
123 if (_returnQuotes)
124 _token.append(c);
125 state=2;
126 }
127 else if (c=='\"' && _double)
128 {
129 if (_returnQuotes)
130 _token.append(c);
131 state=3;
132 }
133 else
134 {
135 _token.append(c);
136 _hasToken=true;
137 state=1;
138 }
139 break;
140
141 case 1:
142 _hasToken=true;
143 if(_delim.indexOf(c)>=0)
144 {
145 if (_returnDelimiters)
146 _i--;
147 return _hasToken;
148 }
149 else if (c=='\'' && _single)
150 {
151 if (_returnQuotes)
152 _token.append(c);
153 state=2;
154 }
155 else if (c=='\"' && _double)
156 {
157 if (_returnQuotes)
158 _token.append(c);
159 state=3;
160 }
161 else
162 {
163 _token.append(c);
164 }
165 break;
166
167 case 2:
168 _hasToken=true;
169 if (escape)
170 {
171 escape=false;
172 _token.append(c);
173 }
174 else if (c=='\'')
175 {
176 if (_returnQuotes)
177 _token.append(c);
178 state=1;
179 }
180 else if (c=='\\')
181 {
182 if (_returnQuotes)
183 _token.append(c);
184 escape=true;
185 }
186 else
187 {
188 _token.append(c);
189 }
190 break;
191
192 case 3:
193 _hasToken=true;
194 if (escape)
195 {
196 escape=false;
197 _token.append(c);
198 }
199 else if (c=='\"')
200 {
201 if (_returnQuotes)
202 _token.append(c);
203 state=1;
204 }
205 else if (c=='\\')
206 {
207 if (_returnQuotes)
208 _token.append(c);
209 escape=true;
210 }
211 else
212 {
213 _token.append(c);
214 }
215 break;
216 }
217 }
218
219 return _hasToken;
220 }
221
222
223 @Override
224 public String nextToken()
225 throws NoSuchElementException
226 {
227 if (!hasMoreTokens() || _token==null)
228 throw new NoSuchElementException();
229 String t=_token.toString();
230 _token.setLength(0);
231 _hasToken=false;
232 return t;
233 }
234
235
236 @Override
237 public String nextToken(String delim)
238 throws NoSuchElementException
239 {
240 _delim=delim;
241 _i=_lastStart;
242 _token.setLength(0);
243 _hasToken=false;
244 return nextToken();
245 }
246
247
248 @Override
249 public boolean hasMoreElements()
250 {
251 return hasMoreTokens();
252 }
253
254
255 @Override
256 public Object nextElement()
257 throws NoSuchElementException
258 {
259 return nextToken();
260 }
261
262
263
264
265 @Override
266 public int countTokens()
267 {
268 return -1;
269 }
270
271
272
273
274
275
276
277
278
279
280
281 public static String quoteIfNeeded(String s, String delim)
282 {
283 if (s==null)
284 return null;
285 if (s.length()==0)
286 return "\"\"";
287
288
289 for (int i=0;i<s.length();i++)
290 {
291 char c = s.charAt(i);
292 if (c=='\\' || c=='"' || c=='\'' || Character.isWhitespace(c) || delim.indexOf(c)>=0)
293 {
294 StringBuffer b=new StringBuffer(s.length()+8);
295 quote(b,s);
296 return b.toString();
297 }
298 }
299
300 return s;
301 }
302
303
304
305
306
307
308
309
310
311 public static String quote(String s)
312 {
313 if (s==null)
314 return null;
315 if (s.length()==0)
316 return "\"\"";
317
318 StringBuffer b=new StringBuffer(s.length()+8);
319 quote(b,s);
320 return b.toString();
321
322 }
323
324 private static final char[] escapes = new char[32];
325 static
326 {
327 Arrays.fill(escapes, (char)0xFFFF);
328 escapes['\b'] = 'b';
329 escapes['\t'] = 't';
330 escapes['\n'] = 'n';
331 escapes['\f'] = 'f';
332 escapes['\r'] = 'r';
333 }
334
335
336
337
338
339
340
341 public static void quote(Appendable buffer, String input)
342 {
343 try
344 {
345 buffer.append('"');
346 for (int i = 0; i < input.length(); ++i)
347 {
348 char c = input.charAt(i);
349 if (c >= 32)
350 {
351 if (c == '"' || c == '\\')
352 buffer.append('\\');
353 buffer.append(c);
354 }
355 else
356 {
357 char escape = escapes[c];
358 if (escape == 0xFFFF)
359 {
360
361 buffer.append('\\').append('u').append('0').append('0');
362 if (c < 0x10)
363 buffer.append('0');
364 buffer.append(Integer.toString(c, 16));
365 }
366 else
367 {
368 buffer.append('\\').append(escape);
369 }
370 }
371 }
372 buffer.append('"');
373 }
374 catch (IOException x)
375 {
376 throw new RuntimeException(x);
377 }
378 }
379
380
381
382
383
384
385
386
387
388
389 public static boolean quoteIfNeeded(Appendable buf, String s,String delim)
390 {
391 for (int i=0;i<s.length();i++)
392 {
393 char c = s.charAt(i);
394 if (delim.indexOf(c)>=0)
395 {
396 quote(buf,s);
397 return true;
398 }
399 }
400
401 try
402 {
403 buf.append(s);
404 return false;
405 }
406 catch(IOException e)
407 {
408 throw new RuntimeException(e);
409 }
410 }
411
412
413
414
415
416
417 public static String unquote(String s)
418 {
419 if (s==null)
420 return null;
421 if (s.length()<2)
422 return s;
423
424 char first=s.charAt(0);
425 char last=s.charAt(s.length()-1);
426 if (first!=last || (first!='"' && first!='\''))
427 return s;
428
429 StringBuilder b = new StringBuilder(s.length() - 2);
430 boolean escape=false;
431 for (int i=1;i<s.length()-1;i++)
432 {
433 char c = s.charAt(i);
434
435 if (escape)
436 {
437 escape=false;
438 switch (c)
439 {
440 case 'n':
441 b.append('\n');
442 break;
443 case 'r':
444 b.append('\r');
445 break;
446 case 't':
447 b.append('\t');
448 break;
449 case 'f':
450 b.append('\f');
451 break;
452 case 'b':
453 b.append('\b');
454 break;
455 case '\\':
456 b.append('\\');
457 break;
458 case '/':
459 b.append('/');
460 break;
461 case '"':
462 b.append('"');
463 break;
464 case 'u':
465 b.append((char)(
466 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<24)+
467 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<16)+
468 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<8)+
469 (TypeUtil.convertHexDigit((byte)s.charAt(i++)))
470 )
471 );
472 break;
473 default:
474 b.append(c);
475 }
476 }
477 else if (c=='\\')
478 {
479 escape=true;
480 }
481 else
482 {
483 b.append(c);
484 }
485 }
486
487 return b.toString();
488 }
489
490
491
492
493
494 public boolean getDouble()
495 {
496 return _double;
497 }
498
499
500
501
502
503 public void setDouble(boolean d)
504 {
505 _double=d;
506 }
507
508
509
510
511
512 public boolean getSingle()
513 {
514 return _single;
515 }
516
517
518
519
520
521 public void setSingle(boolean single)
522 {
523 _single=single;
524 }
525 }