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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util;
21 import java.io.IOException;
22 import java.util.Arrays;
23 import java.util.NoSuchElementException;
24 import java.util.StringTokenizer;
26 /* ------------------------------------------------------------ */
27 /** StringTokenizer with Quoting support.
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 '\'.
35 * @see java.util.StringTokenizer
38 public class QuotedStringTokenizer
39 extends StringTokenizer
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;
49 private int _lastStart=0;
50 private boolean _double=true;
51 private boolean _single=true;
53 /* ------------------------------------------------------------ */
54 public QuotedStringTokenizer(String str,
56 boolean returnDelimiters,
63 _returnDelimiters=returnDelimiters;
64 _returnQuotes=returnQuotes;
66 if (_delim.indexOf('\'')>=0 ||
67 _delim.indexOf('"')>=0)
68 throw new Error("Can't use quotes as delimiters: "+_delim);
70 _token=new StringBuffer(_string.length()>1024?512:_string.length()/2);
73 /* ------------------------------------------------------------ */
74 public QuotedStringTokenizer(String str,
76 boolean returnDelimiters)
78 this(str,delim,returnDelimiters,false);
81 /* ------------------------------------------------------------ */
82 public QuotedStringTokenizer(String str,
85 this(str,delim,false,false);
88 /* ------------------------------------------------------------ */
89 public QuotedStringTokenizer(String str)
91 this(str,null,false,false);
94 /* ------------------------------------------------------------ */
96 public boolean hasMoreTokens()
98 // Already found a token
105 boolean escape=false;
106 while (_i<_string.length())
108 char c=_string.charAt(_i++);
113 if(_delim.indexOf(c)>=0)
115 if (_returnDelimiters)
118 return _hasToken=true;
121 else if (c=='\'' && _single)
127 else if (c=='\"' && _double)
143 if(_delim.indexOf(c)>=0)
145 if (_returnDelimiters)
149 else if (c=='\'' && _single)
155 else if (c=='\"' && _double)
167 case 2: // Single Quote
192 case 3: // Double Quote
222 /* ------------------------------------------------------------ */
224 public String nextToken()
225 throws NoSuchElementException
227 if (!hasMoreTokens() || _token==null)
228 throw new NoSuchElementException();
229 String t=_token.toString();
235 /* ------------------------------------------------------------ */
237 public String nextToken(String delim)
238 throws NoSuchElementException
247 /* ------------------------------------------------------------ */
249 public boolean hasMoreElements()
251 return hasMoreTokens();
254 /* ------------------------------------------------------------ */
256 public Object nextElement()
257 throws NoSuchElementException
262 /* ------------------------------------------------------------ */
266 public int countTokens()
272 /* ------------------------------------------------------------ */
274 * The string is quoted only if quoting is required due to
275 * embedded delimiters, quote characters or the
277 * @param s The string to quote.
278 * @param delim the delimiter to use to quote the string
279 * @return quoted string
281 public static String quoteIfNeeded(String s, String delim)
289 for (int i=0;i<s.length();i++)
291 char c = s.charAt(i);
292 if (c=='\\' || c=='"' || c=='\'' || Character.isWhitespace(c) || delim.indexOf(c)>=0)
294 StringBuffer b=new StringBuffer(s.length()+8);
303 /* ------------------------------------------------------------ */
305 * The string is quoted only if quoting is required due to
306 * embeded delimiters, quote characters or the
308 * @param s The string to quote.
309 * @return quoted string
311 public static String quote(String s)
318 StringBuffer b=new StringBuffer(s.length()+8);
324 private static final char[] escapes = new char[32];
327 Arrays.fill(escapes, (char)0xFFFF);
335 /* ------------------------------------------------------------ */
336 /** Quote a string into an Appendable.
337 * Only quotes and backslash are escaped.
338 * @param buffer The Appendable
339 * @param input The String to quote.
341 public static void quoteOnly(Appendable buffer, String input)
349 for (int i = 0; i < input.length(); ++i)
351 char c = input.charAt(i);
352 if (c == '"' || c == '\\')
358 catch (IOException x)
360 throw new RuntimeException(x);
364 /* ------------------------------------------------------------ */
365 /** Quote a string into an Appendable.
366 * The characters ", \, \n, \r, \t, \f and \b are escaped
367 * @param buffer The Appendable
368 * @param input The String to quote.
370 public static void quote(Appendable buffer, String input)
378 for (int i = 0; i < input.length(); ++i)
380 char c = input.charAt(i);
383 if (c == '"' || c == '\\')
389 char escape = escapes[c];
390 if (escape == 0xFFFF)
393 buffer.append('\\').append('u').append('0').append('0');
396 buffer.append(Integer.toString(c, 16));
400 buffer.append('\\').append(escape);
406 catch (IOException x)
408 throw new RuntimeException(x);
413 /* ------------------------------------------------------------ */
414 public static String unquoteOnly(String s)
416 return unquoteOnly(s, false);
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
426 public static String unquoteOnly(String s, boolean lenient)
433 char first=s.charAt(0);
434 char last=s.charAt(s.length()-1);
435 if (first!=last || (first!='"' && first!='\''))
438 StringBuilder b = new StringBuilder(s.length() - 2);
439 boolean escape=false;
440 for (int i=1;i<s.length()-1;i++)
442 char c = s.charAt(i);
447 if (lenient && !isValidEscaping(c))
466 /* ------------------------------------------------------------ */
467 public static String unquote(String s)
469 return unquote(s,false);
472 /* ------------------------------------------------------------ */
473 /** Unquote a string.
474 * @param s The string to unquote.
475 * @return quoted string
477 public static String unquote(String s, boolean lenient)
484 char first=s.charAt(0);
485 char last=s.charAt(s.length()-1);
486 if (first!=last || (first!='"' && first!='\''))
489 StringBuilder b = new StringBuilder(s.length() - 2);
490 boolean escape=false;
491 for (int i=1;i<s.length()-1;i++)
493 char c = s.charAt(i);
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++)))
534 if (lenient && !isValidEscaping(c))
555 /* ------------------------------------------------------------ */
556 /** Check that char c (which is preceded by a backslash) is a valid
561 private static boolean isValidEscaping(char c)
563 return ((c == 'n') || (c == 'r') || (c == 't') ||
564 (c == 'f') || (c == 'b') || (c == '\\') ||
565 (c == '/') || (c == '"') || (c == 'u'));
568 /* ------------------------------------------------------------ */
569 public static boolean isQuoted(String s)
571 return s!=null && s.length()>0 && s.charAt(0)=='"' && s.charAt(s.length()-1)=='"';
574 /* ------------------------------------------------------------ */
576 * @return handle double quotes if true
578 public boolean getDouble()
583 /* ------------------------------------------------------------ */
585 * @param d handle double quotes if true
587 public void setDouble(boolean d)
592 /* ------------------------------------------------------------ */
594 * @return handle single quotes if true
596 public boolean getSingle()
601 /* ------------------------------------------------------------ */
603 * @param single handle single quotes if true
605 public void setSingle(boolean single)