Mercurial Hosting > luan
comparison src/org/eclipse/jetty/util/QuotedStringTokenizer.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
801:6a21393191c1 | 802:3428c60d7cfc |
---|---|
1 // | |
2 // ======================================================================== | |
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. | |
4 // ------------------------------------------------------------------------ | |
5 // All rights reserved. This program and the accompanying materials | |
6 // are made available under the terms of the Eclipse Public License v1.0 | |
7 // and Apache License v2.0 which accompanies this distribution. | |
8 // | |
9 // The Eclipse Public License is available at | |
10 // http://www.eclipse.org/legal/epl-v10.html | |
11 // | |
12 // The Apache License v2.0 is available at | |
13 // http://www.opensource.org/licenses/apache2.0.php | |
14 // | |
15 // You may elect to redistribute this code under either of these licenses. | |
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 /** StringTokenizer with Quoting support. | |
28 * | |
29 * This class is a copy of the java.util.StringTokenizer API and | |
30 * the behaviour is the same, except that single and double quoted | |
31 * string values are recognised. | |
32 * Delimiters within quotes are not considered delimiters. | |
33 * Quotes can be escaped with '\'. | |
34 * | |
35 * @see java.util.StringTokenizer | |
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 // Already found a token | |
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: // Start | |
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: // Token | |
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: // Single Quote | |
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: // Double Quote | |
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 /** Not implemented. | |
264 */ | |
265 @Override | |
266 public int countTokens() | |
267 { | |
268 return -1; | |
269 } | |
270 | |
271 | |
272 /* ------------------------------------------------------------ */ | |
273 /** Quote a string. | |
274 * The string is quoted only if quoting is required due to | |
275 * embedded delimiters, quote characters or the | |
276 * empty string. | |
277 * @param s The string to quote. | |
278 * @param delim the delimiter to use to quote the string | |
279 * @return quoted string | |
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 /** Quote a string. | |
305 * The string is quoted only if quoting is required due to | |
306 * embeded delimiters, quote characters or the | |
307 * empty string. | |
308 * @param s The string to quote. | |
309 * @return quoted string | |
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 /** Quote a string into an Appendable. | |
337 * The characters ", \, \n, \r, \t, \f and \b are escaped | |
338 * @param buffer The Appendable | |
339 * @param input The String to quote. | |
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 // Unicode escape | |
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 /** Quote a string into a StringBuffer only if needed. | |
382 * Quotes are forced if any delim characters are present. | |
383 * | |
384 * @param buf The StringBuffer | |
385 * @param s The String to quote. | |
386 * @param delim String of characters that must be quoted. | |
387 * @return true if quoted; | |
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 public static String unquoteOnly(String s) | |
415 { | |
416 return unquoteOnly(s, false); | |
417 } | |
418 | |
419 | |
420 /* ------------------------------------------------------------ */ | |
421 /** Unquote a string, NOT converting unicode sequences | |
422 * @param s The string to unquote. | |
423 * @param lenient if true, will leave in backslashes that aren't valid escapes | |
424 * @return quoted string | |
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 /** Unquote a string. | |
474 * @param s The string to unquote. | |
475 * @return quoted string | |
476 */ | |
477 public static String unquote(String s, boolean lenient) | |
478 { | |
479 if (s==null) | |
480 return null; | |
481 if (s.length()<2) | |
482 return s; | |
483 | |
484 char first=s.charAt(0); | |
485 char last=s.charAt(s.length()-1); | |
486 if (first!=last || (first!='"' && first!='\'')) | |
487 return s; | |
488 | |
489 StringBuilder b = new StringBuilder(s.length() - 2); | |
490 boolean escape=false; | |
491 for (int i=1;i<s.length()-1;i++) | |
492 { | |
493 char c = s.charAt(i); | |
494 | |
495 if (escape) | |
496 { | |
497 escape=false; | |
498 switch (c) | |
499 { | |
500 case 'n': | |
501 b.append('\n'); | |
502 break; | |
503 case 'r': | |
504 b.append('\r'); | |
505 break; | |
506 case 't': | |
507 b.append('\t'); | |
508 break; | |
509 case 'f': | |
510 b.append('\f'); | |
511 break; | |
512 case 'b': | |
513 b.append('\b'); | |
514 break; | |
515 case '\\': | |
516 b.append('\\'); | |
517 break; | |
518 case '/': | |
519 b.append('/'); | |
520 break; | |
521 case '"': | |
522 b.append('"'); | |
523 break; | |
524 case 'u': | |
525 b.append((char)( | |
526 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<24)+ | |
527 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<16)+ | |
528 (TypeUtil.convertHexDigit((byte)s.charAt(i++))<<8)+ | |
529 (TypeUtil.convertHexDigit((byte)s.charAt(i++))) | |
530 ) | |
531 ); | |
532 break; | |
533 default: | |
534 if (lenient && !isValidEscaping(c)) | |
535 { | |
536 b.append('\\'); | |
537 } | |
538 b.append(c); | |
539 } | |
540 } | |
541 else if (c=='\\') | |
542 { | |
543 escape=true; | |
544 } | |
545 else | |
546 { | |
547 b.append(c); | |
548 } | |
549 } | |
550 | |
551 return b.toString(); | |
552 } | |
553 | |
554 | |
555 /* ------------------------------------------------------------ */ | |
556 /** Check that char c (which is preceded by a backslash) is a valid | |
557 * escape sequence. | |
558 * @param c | |
559 * @return | |
560 */ | |
561 private static boolean isValidEscaping(char c) | |
562 { | |
563 return ((c == 'n') || (c == 'r') || (c == 't') || | |
564 (c == 'f') || (c == 'b') || (c == '\\') || | |
565 (c == '/') || (c == '"') || (c == 'u')); | |
566 } | |
567 | |
568 /* ------------------------------------------------------------ */ | |
569 /** | |
570 * @return handle double quotes if true | |
571 */ | |
572 public boolean getDouble() | |
573 { | |
574 return _double; | |
575 } | |
576 | |
577 /* ------------------------------------------------------------ */ | |
578 /** | |
579 * @param d handle double quotes if true | |
580 */ | |
581 public void setDouble(boolean d) | |
582 { | |
583 _double=d; | |
584 } | |
585 | |
586 /* ------------------------------------------------------------ */ | |
587 /** | |
588 * @return handle single quotes if true | |
589 */ | |
590 public boolean getSingle() | |
591 { | |
592 return _single; | |
593 } | |
594 | |
595 /* ------------------------------------------------------------ */ | |
596 /** | |
597 * @param single handle single quotes if true | |
598 */ | |
599 public void setSingle(boolean single) | |
600 { | |
601 _single=single; | |
602 } | |
603 } |