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