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 } |
