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