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 quoteOnly(Appendable buffer, String input)
342 {
343 if(input==null)
344 return;
345
346 try
347 {
348 buffer.append('"');
349 for (int i = 0; i < input.length(); ++i)
350 {
351 char c = input.charAt(i);
352 if (c == '"' || c == '\\')
353 buffer.append('\\');
354 buffer.append(c);
355 }
356 buffer.append('"');
357 }
358 catch (IOException x)
359 {
360 throw new RuntimeException(x);
361 }
362 }
363
364
365
366
367
368
369
370 public static void quote(Appendable buffer, String input)
371 {
372 if(input==null)
373 return;
374
375 try
376 {
377 buffer.append('"');
378 for (int i = 0; i < input.length(); ++i)
379 {
380 char c = input.charAt(i);
381 if (c >= 32)
382 {
383 if (c == '"' || c == '\\')
384 buffer.append('\\');
385 buffer.append(c);
386 }
387 else
388 {
389 char escape = escapes[c];
390 if (escape == 0xFFFF)
391 {
392
393 buffer.append('\\').append('u').append('0').append('0');
394 if (c < 0x10)
395 buffer.append('0');
396 buffer.append(Integer.toString(c, 16));
397 }
398 else
399 {
400 buffer.append('\\').append(escape);
401 }
402 }
403 }
404 buffer.append('"');
405 }
406 catch (IOException x)
407 {
408 throw new RuntimeException(x);
409 }
410 }
411
412
413
414 public static String unquoteOnly(String s)
415 {
416 return unquoteOnly(s, false);
417 }
418
419
420
421
422
423
424
425
426 public static String unquoteOnly(String s, boolean lenient)
427 {
428 if (s==null)
429 return null;
430 if (s.length()<2)
431 return s;
432
433 char first=s.charAt(0);
434 char last=s.charAt(s.length()-1);
435 if (first!=last || (first!='"' && first!='\''))
436 return s;
437
438 StringBuilder b = new StringBuilder(s.length() - 2);
439 boolean escape=false;
440 for (int i=1;i<s.length()-1;i++)
441 {
442 char c = s.charAt(i);
443
444 if (escape)
445 {
446 escape=false;
447 if (lenient && !isValidEscaping(c))
448 {
449 b.append('\\');
450 }
451 b.append(c);
452 }
453 else if (c=='\\')
454 {
455 escape=true;
456 }
457 else
458 {
459 b.append(c);
460 }
461 }
462
463 return b.toString();
464 }
465
466
467 public static String unquote(String s)
468 {
469 return unquote(s,false);
470 }
471
472
473
474
475
476
477
478 public static String unquote(String s, boolean lenient)
479 {
480 if (s==null)
481 return null;
482 if (s.length()<2)
483 return s;
484
485 char first=s.charAt(0);
486 char last=s.charAt(s.length()-1);
487 if (first!=last || (first!='"' && first!='\''))
488 return s;
489
490 StringBuilder b = new StringBuilder(s.length() - 2);
491 boolean escape=false;
492 for (int i=1;i<s.length()-1;i++)
493 {
494 char c = s.charAt(i);
495
496 if (escape)
497 {
498 escape=false;
499 switch (c)
500 {
501 case 'n':
502 b.append('\n');
503 break;
504 case 'r':
505 b.append('\r');
506 break;
507 case 't':
508 b.append('\t');
509 break;
510 case 'f':
511 b.append('\f');
512 break;
513 case 'b':
514 b.append('\b');
515 break;
516 case '\\':
517 b.append('\\');
518 break;
519 case '/':
520 b.append('/');
521 break;
522 case '"':
523 b.append('"');
524 break;
525 case 'u':
526 b.append((char)(
527 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<24)+
528 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<16)+
529 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<8)+
530 (TypeUtil.convertHexDigit((byte)s.charAt(i++)))
531 )
532 );
533 break;
534 default:
535 if (lenient && !isValidEscaping(c))
536 {
537 b.append('\\');
538 }
539 b.append(c);
540 }
541 }
542 else if (c=='\\')
543 {
544 escape=true;
545 }
546 else
547 {
548 b.append(c);
549 }
550 }
551
552 return b.toString();
553 }
554
555
556
557
558
559
560
561
562 private static boolean isValidEscaping(char c)
563 {
564 return ((c == 'n') || (c == 'r') || (c == 't') ||
565 (c == 'f') || (c == 'b') || (c == '\\') ||
566 (c == '/') || (c == '"') || (c == 'u'));
567 }
568
569
570 public static boolean isQuoted(String s)
571 {
572 return s!=null && s.length()>0 && s.charAt(0)=='"' && s.charAt(s.length()-1)=='"';
573 }
574
575
576
577
578
579 public boolean getDouble()
580 {
581 return _double;
582 }
583
584
585
586
587
588 public void setDouble(boolean d)
589 {
590 _double=d;
591 }
592
593
594
595
596
597 public boolean getSingle()
598 {
599 return _single;
600 }
601
602
603
604
605
606 public void setSingle(boolean single)
607 {
608 _single=single;
609 }
610 }