Fixes #353862 (Improve performance of QuotedStringTokenizer.quote()).
This commit is contained in:
parent
3d9ebd7803
commit
01cbaf528b
|
@ -14,7 +14,8 @@ jetty-7.5.0-SNAPSHOT
|
||||||
+ 353210 Bundle-Version in o.e.j.o.boot.logback fix
|
+ 353210 Bundle-Version in o.e.j.o.boot.logback fix
|
||||||
+ 353465 JAASLoginService ignores callbackHandlerClass
|
+ 353465 JAASLoginService ignores callbackHandlerClass
|
||||||
+ 353563 HttpDestinationQueueTest too slow
|
+ 353563 HttpDestinationQueueTest too slow
|
||||||
|
+ 353862 Improve performance of QuotedStringTokenizer.quote()
|
||||||
|
|
||||||
jetty-7.4.4.v20110707 July 7th 2011
|
jetty-7.4.4.v20110707 July 7th 2011
|
||||||
+ 308851 Converted all jetty-client module tests to JUnit 4
|
+ 308851 Converted all jetty-client module tests to JUnit 4
|
||||||
+ 345268 JDBCSessionManager does not work with maxInactiveInterval = -1
|
+ 345268 JDBCSessionManager does not work with maxInactiveInterval = -1
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
// All rights reserved. This program and the accompanying materials
|
// All rights reserved. This program and the accompanying materials
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
// The Eclipse Public License is available at
|
// The Eclipse Public License is available at
|
||||||
// http://www.eclipse.org/legal/epl-v10.html
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
// The Apache License v2.0 is available at
|
// The Apache License v2.0 is available at
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
// You may elect to redistribute this code under either of these licenses.
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
package org.eclipse.jetty.util;
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ import java.util.StringTokenizer;
|
||||||
* Quotes can be escaped with '\'.
|
* Quotes can be escaped with '\'.
|
||||||
*
|
*
|
||||||
* @see java.util.StringTokenizer
|
* @see java.util.StringTokenizer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class QuotedStringTokenizer
|
public class QuotedStringTokenizer
|
||||||
extends StringTokenizer
|
extends StringTokenizer
|
||||||
|
@ -43,7 +44,7 @@ public class QuotedStringTokenizer
|
||||||
private int _lastStart=0;
|
private int _lastStart=0;
|
||||||
private boolean _double=true;
|
private boolean _double=true;
|
||||||
private boolean _single=true;
|
private boolean _single=true;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public QuotedStringTokenizer(String str,
|
public QuotedStringTokenizer(String str,
|
||||||
String delim,
|
String delim,
|
||||||
|
@ -56,11 +57,11 @@ public class QuotedStringTokenizer
|
||||||
_delim=delim;
|
_delim=delim;
|
||||||
_returnDelimiters=returnDelimiters;
|
_returnDelimiters=returnDelimiters;
|
||||||
_returnQuotes=returnQuotes;
|
_returnQuotes=returnQuotes;
|
||||||
|
|
||||||
if (_delim.indexOf('\'')>=0 ||
|
if (_delim.indexOf('\'')>=0 ||
|
||||||
_delim.indexOf('"')>=0)
|
_delim.indexOf('"')>=0)
|
||||||
throw new Error("Can't use quotes as delimiters: "+_delim);
|
throw new Error("Can't use quotes as delimiters: "+_delim);
|
||||||
|
|
||||||
_token=new StringBuffer(_string.length()>1024?512:_string.length()/2);
|
_token=new StringBuffer(_string.length()>1024?512:_string.length()/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ public class QuotedStringTokenizer
|
||||||
{
|
{
|
||||||
this(str,delim,returnDelimiters,false);
|
this(str,delim,returnDelimiters,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public QuotedStringTokenizer(String str,
|
public QuotedStringTokenizer(String str,
|
||||||
String delim)
|
String delim)
|
||||||
|
@ -92,15 +93,15 @@ public class QuotedStringTokenizer
|
||||||
// Already found a token
|
// Already found a token
|
||||||
if (_hasToken)
|
if (_hasToken)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
_lastStart=_i;
|
_lastStart=_i;
|
||||||
|
|
||||||
int state=0;
|
int state=0;
|
||||||
boolean escape=false;
|
boolean escape=false;
|
||||||
while (_i<_string.length())
|
while (_i<_string.length())
|
||||||
{
|
{
|
||||||
char c=_string.charAt(_i++);
|
char c=_string.charAt(_i++);
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case 0: // Start
|
case 0: // Start
|
||||||
|
@ -130,8 +131,8 @@ public class QuotedStringTokenizer
|
||||||
_hasToken=true;
|
_hasToken=true;
|
||||||
state=1;
|
state=1;
|
||||||
}
|
}
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
case 1: // Token
|
case 1: // Token
|
||||||
_hasToken=true;
|
_hasToken=true;
|
||||||
if(_delim.indexOf(c)>=0)
|
if(_delim.indexOf(c)>=0)
|
||||||
|
@ -153,10 +154,11 @@ public class QuotedStringTokenizer
|
||||||
state=3;
|
state=3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_token.append(c);
|
_token.append(c);
|
||||||
continue;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 2: // Single Quote
|
case 2: // Single Quote
|
||||||
_hasToken=true;
|
_hasToken=true;
|
||||||
if (escape)
|
if (escape)
|
||||||
|
@ -177,10 +179,11 @@ public class QuotedStringTokenizer
|
||||||
escape=true;
|
escape=true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_token.append(c);
|
_token.append(c);
|
||||||
continue;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 3: // Double Quote
|
case 3: // Double Quote
|
||||||
_hasToken=true;
|
_hasToken=true;
|
||||||
if (escape)
|
if (escape)
|
||||||
|
@ -201,8 +204,10 @@ public class QuotedStringTokenizer
|
||||||
escape=true;
|
escape=true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_token.append(c);
|
_token.append(c);
|
||||||
continue;
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +217,7 @@ public class QuotedStringTokenizer
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public String nextToken()
|
public String nextToken()
|
||||||
throws NoSuchElementException
|
throws NoSuchElementException
|
||||||
{
|
{
|
||||||
if (!hasMoreTokens() || _token==null)
|
if (!hasMoreTokens() || _token==null)
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
|
@ -225,7 +230,7 @@ public class QuotedStringTokenizer
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public String nextToken(String delim)
|
public String nextToken(String delim)
|
||||||
throws NoSuchElementException
|
throws NoSuchElementException
|
||||||
{
|
{
|
||||||
_delim=delim;
|
_delim=delim;
|
||||||
_i=_lastStart;
|
_i=_lastStart;
|
||||||
|
@ -244,7 +249,7 @@ public class QuotedStringTokenizer
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public Object nextElement()
|
public Object nextElement()
|
||||||
throws NoSuchElementException
|
throws NoSuchElementException
|
||||||
{
|
{
|
||||||
return nextToken();
|
return nextToken();
|
||||||
}
|
}
|
||||||
|
@ -258,13 +263,14 @@ public class QuotedStringTokenizer
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Quote a string.
|
/** Quote a string.
|
||||||
* The string is quoted only if quoting is required due to
|
* The string is quoted only if quoting is required due to
|
||||||
* embeded delimiters, quote characters or the
|
* embedded delimiters, quote characters or the
|
||||||
* empty string.
|
* empty string.
|
||||||
* @param s The string to quote.
|
* @param s The string to quote.
|
||||||
|
* @param delim the delimiter to use to quote the string
|
||||||
* @return quoted string
|
* @return quoted string
|
||||||
*/
|
*/
|
||||||
public static String quoteIfNeeded(String s, String delim)
|
public static String quoteIfNeeded(String s, String delim)
|
||||||
|
@ -274,7 +280,7 @@ public class QuotedStringTokenizer
|
||||||
if (s.length()==0)
|
if (s.length()==0)
|
||||||
return "\"\"";
|
return "\"\"";
|
||||||
|
|
||||||
|
|
||||||
for (int i=0;i<s.length();i++)
|
for (int i=0;i<s.length();i++)
|
||||||
{
|
{
|
||||||
char c = s.charAt(i);
|
char c = s.charAt(i);
|
||||||
|
@ -285,7 +291,7 @@ public class QuotedStringTokenizer
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,81 +309,73 @@ public class QuotedStringTokenizer
|
||||||
return null;
|
return null;
|
||||||
if (s.length()==0)
|
if (s.length()==0)
|
||||||
return "\"\"";
|
return "\"\"";
|
||||||
|
|
||||||
StringBuffer b=new StringBuffer(s.length()+8);
|
StringBuffer b=new StringBuffer(s.length()+8);
|
||||||
quote(b,s);
|
quote(b,s);
|
||||||
return b.toString();
|
return b.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final char[] escapes = new char[31];
|
||||||
|
static
|
||||||
|
{
|
||||||
|
Arrays.fill(escapes, (char)-1);
|
||||||
|
escapes['\b'] = 'b';
|
||||||
|
escapes['\t'] = 't';
|
||||||
|
escapes['\n'] = 'n';
|
||||||
|
escapes['\f'] = 'f';
|
||||||
|
escapes['\r'] = 'r';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Quote a string into an Appendable.
|
/** Quote a string into an Appendable.
|
||||||
* The characters ", \, \n, \r, \t, \f and \b are escaped
|
* The characters ", \, \n, \r, \t, \f and \b are escaped
|
||||||
* @param buf The Appendable
|
* @param buffer The Appendable
|
||||||
* @param s The String to quote.
|
* @param input The String to quote.
|
||||||
*/
|
*/
|
||||||
public static void quote(Appendable buf, String s)
|
public static void quote(Appendable buffer, String input)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
buf.append('"');
|
buffer.append('"');
|
||||||
|
for (int i = 0; i < input.length(); ++i)
|
||||||
for (int i=0;i<s.length();i++)
|
|
||||||
{
|
{
|
||||||
char c = s.charAt(i);
|
char c = input.charAt(i);
|
||||||
switch(c)
|
if (c >= 32)
|
||||||
{
|
{
|
||||||
case '"':
|
if (c == '"' || c == '\\')
|
||||||
buf.append("\\\"");
|
buffer.append('\\');
|
||||||
continue;
|
buffer.append(c);
|
||||||
case '\\':
|
}
|
||||||
buf.append("\\\\");
|
else
|
||||||
continue;
|
{
|
||||||
case '\n':
|
char escape = escapes[c];
|
||||||
buf.append("\\n");
|
if (escape == -1)
|
||||||
continue;
|
{
|
||||||
case '\r':
|
// Unicode escape
|
||||||
buf.append("\\r");
|
buffer.append('\\').append('0').append('0');
|
||||||
continue;
|
if (c < 0x10)
|
||||||
case '\t':
|
buffer.append('0');
|
||||||
buf.append("\\t");
|
buffer.append(Integer.toString(c, 16));
|
||||||
continue;
|
}
|
||||||
case '\f':
|
else
|
||||||
buf.append("\\f");
|
{
|
||||||
continue;
|
buffer.append('\\').append(escape);
|
||||||
case '\b':
|
}
|
||||||
buf.append("\\b");
|
|
||||||
continue;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (c<0x10)
|
|
||||||
{
|
|
||||||
buf.append("\\u000");
|
|
||||||
buf.append(Integer.toString(c,16));
|
|
||||||
}
|
|
||||||
else if (c<=0x1f)
|
|
||||||
{
|
|
||||||
buf.append("\\u00");
|
|
||||||
buf.append(Integer.toString(c,16));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
buf.append(c);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
buffer.append('"');
|
||||||
buf.append('"');
|
}
|
||||||
}
|
catch (IOException x)
|
||||||
catch(IOException e)
|
|
||||||
{
|
{
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Quote a string into a StringBuffer only if needed.
|
/** Quote a string into a StringBuffer only if needed.
|
||||||
* Quotes are forced if any delim characters are present.
|
* Quotes are forced if any delim characters are present.
|
||||||
*
|
*
|
||||||
* @param buf The StringBuffer
|
* @param buf The StringBuffer
|
||||||
* @param s The String to quote.
|
* @param s The String to quote.
|
||||||
* @param delim String of characters that must be quoted.
|
* @param delim String of characters that must be quoted.
|
||||||
|
@ -394,7 +392,7 @@ public class QuotedStringTokenizer
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
buf.append(s);
|
buf.append(s);
|
||||||
|
@ -405,7 +403,7 @@ public class QuotedStringTokenizer
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Unquote a string.
|
/** Unquote a string.
|
||||||
* @param s The string to unquote.
|
* @param s The string to unquote.
|
||||||
|
@ -422,68 +420,66 @@ public class QuotedStringTokenizer
|
||||||
char last=s.charAt(s.length()-1);
|
char last=s.charAt(s.length()-1);
|
||||||
if (first!=last || (first!='"' && first!='\''))
|
if (first!=last || (first!='"' && first!='\''))
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
StringBuffer b=new StringBuffer(s.length()-2);
|
|
||||||
synchronized(b)
|
|
||||||
{
|
|
||||||
boolean escape=false;
|
|
||||||
for (int i=1;i<s.length()-1;i++)
|
|
||||||
{
|
|
||||||
char c = s.charAt(i);
|
|
||||||
|
|
||||||
if (escape)
|
StringBuilder b = new StringBuilder(s.length() - 2);
|
||||||
|
boolean escape=false;
|
||||||
|
for (int i=1;i<s.length()-1;i++)
|
||||||
|
{
|
||||||
|
char c = s.charAt(i);
|
||||||
|
|
||||||
|
if (escape)
|
||||||
|
{
|
||||||
|
escape=false;
|
||||||
|
switch (c)
|
||||||
{
|
{
|
||||||
escape=false;
|
case 'n':
|
||||||
switch (c)
|
b.append('\n');
|
||||||
{
|
break;
|
||||||
case 'n':
|
case 'r':
|
||||||
b.append('\n');
|
b.append('\r');
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 't':
|
||||||
b.append('\r');
|
b.append('\t');
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 'f':
|
||||||
b.append('\t');
|
b.append('\f');
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'b':
|
||||||
b.append('\f');
|
b.append('\b');
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case '\\':
|
||||||
b.append('\b');
|
b.append('\\');
|
||||||
break;
|
break;
|
||||||
case '\\':
|
case '/':
|
||||||
b.append('\\');
|
b.append('/');
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '"':
|
||||||
b.append('/');
|
b.append('"');
|
||||||
break;
|
break;
|
||||||
case '"':
|
case 'u':
|
||||||
b.append('"');
|
b.append((char)(
|
||||||
break;
|
(TypeUtil.convertHexDigit((byte)s.charAt(i++))<<24)+
|
||||||
case 'u':
|
(TypeUtil.convertHexDigit((byte)s.charAt(i++))<<16)+
|
||||||
b.append((char)(
|
(TypeUtil.convertHexDigit((byte)s.charAt(i++))<<8)+
|
||||||
(TypeUtil.convertHexDigit((byte)s.charAt(i++))<<24)+
|
(TypeUtil.convertHexDigit((byte)s.charAt(i++)))
|
||||||
(TypeUtil.convertHexDigit((byte)s.charAt(i++))<<16)+
|
)
|
||||||
(TypeUtil.convertHexDigit((byte)s.charAt(i++))<<8)+
|
);
|
||||||
(TypeUtil.convertHexDigit((byte)s.charAt(i++)))
|
break;
|
||||||
)
|
default:
|
||||||
);
|
b.append(c);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
b.append(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (c=='\\')
|
|
||||||
{
|
|
||||||
escape=true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
b.append(c);
|
|
||||||
}
|
}
|
||||||
|
else if (c=='\\')
|
||||||
return b.toString();
|
{
|
||||||
|
escape=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b.append(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -522,15 +518,3 @@ public class QuotedStringTokenizer
|
||||||
_single=single;
|
_single=single;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue