1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util;
20
21 import java.io.UnsupportedEncodingException;
22 import java.nio.ByteBuffer;
23 import java.nio.charset.Charset;
24
25 import org.eclipse.jetty.util.log.Log;
26 import org.eclipse.jetty.util.log.Logger;
27
28
29
30
31
32
33
34
35
36
37 public class StringUtil
38 {
39 private static final Logger LOG = Log.getLogger(StringUtil.class);
40
41
42 private final static StringMap<String> CHARSETS= new StringMap<String>(true);
43
44 public static final String ALL_INTERFACES="0.0.0.0";
45 public static final String CRLF="\015\012";
46 public static final String __LINE_SEPARATOR=
47 System.getProperty("line.separator","\n");
48
49 public static final String __ISO_8859_1="ISO-8859-1";
50 public final static String __UTF8="UTF-8";
51 public final static String __UTF16="UTF-16";
52
53 public final static Charset __UTF8_CHARSET;
54 public final static Charset __ISO_8859_1_CHARSET;
55 public final static Charset __UTF16_CHARSET;
56
57 static
58 {
59 __UTF8_CHARSET=Charset.forName(__UTF8);
60 __ISO_8859_1_CHARSET=Charset.forName(__ISO_8859_1);
61 __UTF16_CHARSET=Charset.forName(__UTF16);
62
63 CHARSETS.put("UTF-8",__UTF8);
64 CHARSETS.put("UTF8",__UTF8);
65 CHARSETS.put("UTF-16",__UTF16);
66 CHARSETS.put("UTF16",__UTF16);
67 CHARSETS.put("ISO-8859-1",__ISO_8859_1);
68 CHARSETS.put("ISO_8859_1",__ISO_8859_1);
69 }
70
71
72
73
74
75 public static String normalizeCharset(String s)
76 {
77 String n=CHARSETS.get(s);
78 return (n==null)?s:n;
79 }
80
81
82
83
84
85 public static String normalizeCharset(String s,int offset,int length)
86 {
87 String n=CHARSETS.get(s,offset,length);
88 return (n==null)?s.substring(offset,offset+length):n;
89 }
90
91
92
93
94
95 public static String normalizeCharset(ByteBuffer b,int position,int length)
96 {
97 ByteBuffer ro=b.asReadOnlyBuffer();
98 ro.limit(ro.capacity());
99 ro.position(position);
100 ro.limit(position+length);
101 String n=CHARSETS.get(ro);
102 if (n!=null)
103 return n;
104 ByteBuffer slice = b.slice();
105 slice.position(position);
106 slice.limit(position+length);
107 return BufferUtil.toString(slice,__UTF8_CHARSET);
108 }
109
110
111
112 public static char[] lowercases = {
113 '\000','\001','\002','\003','\004','\005','\006','\007',
114 '\010','\011','\012','\013','\014','\015','\016','\017',
115 '\020','\021','\022','\023','\024','\025','\026','\027',
116 '\030','\031','\032','\033','\034','\035','\036','\037',
117 '\040','\041','\042','\043','\044','\045','\046','\047',
118 '\050','\051','\052','\053','\054','\055','\056','\057',
119 '\060','\061','\062','\063','\064','\065','\066','\067',
120 '\070','\071','\072','\073','\074','\075','\076','\077',
121 '\100','\141','\142','\143','\144','\145','\146','\147',
122 '\150','\151','\152','\153','\154','\155','\156','\157',
123 '\160','\161','\162','\163','\164','\165','\166','\167',
124 '\170','\171','\172','\133','\134','\135','\136','\137',
125 '\140','\141','\142','\143','\144','\145','\146','\147',
126 '\150','\151','\152','\153','\154','\155','\156','\157',
127 '\160','\161','\162','\163','\164','\165','\166','\167',
128 '\170','\171','\172','\173','\174','\175','\176','\177' };
129
130
131
132
133
134
135
136 public static String asciiToLowerCase(String s)
137 {
138 char[] c = null;
139 int i=s.length();
140
141
142 while (i-->0)
143 {
144 char c1=s.charAt(i);
145 if (c1<=127)
146 {
147 char c2=lowercases[c1];
148 if (c1!=c2)
149 {
150 c=s.toCharArray();
151 c[i]=c2;
152 break;
153 }
154 }
155 }
156
157 while (i-->0)
158 {
159 if(c[i]<=127)
160 c[i] = lowercases[c[i]];
161 }
162
163 return c==null?s:new String(c);
164 }
165
166
167
168 public static boolean startsWithIgnoreCase(String s,String w)
169 {
170 if (w==null)
171 return true;
172
173 if (s==null || s.length()<w.length())
174 return false;
175
176 for (int i=0;i<w.length();i++)
177 {
178 char c1=s.charAt(i);
179 char c2=w.charAt(i);
180 if (c1!=c2)
181 {
182 if (c1<=127)
183 c1=lowercases[c1];
184 if (c2<=127)
185 c2=lowercases[c2];
186 if (c1!=c2)
187 return false;
188 }
189 }
190 return true;
191 }
192
193
194 public static boolean endsWithIgnoreCase(String s,String w)
195 {
196 if (w==null)
197 return true;
198
199 if (s==null)
200 return false;
201
202 int sl=s.length();
203 int wl=w.length();
204
205 if (sl<wl)
206 return false;
207
208 for (int i=wl;i-->0;)
209 {
210 char c1=s.charAt(--sl);
211 char c2=w.charAt(i);
212 if (c1!=c2)
213 {
214 if (c1<=127)
215 c1=lowercases[c1];
216 if (c2<=127)
217 c2=lowercases[c2];
218 if (c1!=c2)
219 return false;
220 }
221 }
222 return true;
223 }
224
225
226
227
228
229 public static int indexFrom(String s,String chars)
230 {
231 for (int i=0;i<s.length();i++)
232 if (chars.indexOf(s.charAt(i))>=0)
233 return i;
234 return -1;
235 }
236
237
238
239
240
241 public static String replace(String s, String sub, String with)
242 {
243 int c=0;
244 int i=s.indexOf(sub,c);
245 if (i == -1)
246 return s;
247
248 StringBuilder buf = new StringBuilder(s.length()+with.length());
249
250 do
251 {
252 buf.append(s.substring(c,i));
253 buf.append(with);
254 c=i+sub.length();
255 } while ((i=s.indexOf(sub,c))!=-1);
256
257 if (c<s.length())
258 buf.append(s.substring(c,s.length()));
259
260 return buf.toString();
261
262 }
263
264
265
266
267
268 public static String unquote(String s)
269 {
270 return QuotedStringTokenizer.unquote(s);
271 }
272
273
274
275
276
277
278
279
280
281 public static void append(StringBuilder buf,
282 String s,
283 int offset,
284 int length)
285 {
286 synchronized(buf)
287 {
288 int end=offset+length;
289 for (int i=offset; i<end;i++)
290 {
291 if (i>=s.length())
292 break;
293 buf.append(s.charAt(i));
294 }
295 }
296 }
297
298
299
300
301
302
303
304 public static void append(StringBuilder buf,byte b,int base)
305 {
306 int bi=0xff&b;
307 int c='0'+(bi/base)%base;
308 if (c>'9')
309 c= 'a'+(c-'0'-10);
310 buf.append((char)c);
311 c='0'+bi%base;
312 if (c>'9')
313 c= 'a'+(c-'0'-10);
314 buf.append((char)c);
315 }
316
317
318 public static void append2digits(StringBuffer buf,int i)
319 {
320 if (i<100)
321 {
322 buf.append((char)(i/10+'0'));
323 buf.append((char)(i%10+'0'));
324 }
325 }
326
327
328 public static void append2digits(StringBuilder buf,int i)
329 {
330 if (i<100)
331 {
332 buf.append((char)(i/10+'0'));
333 buf.append((char)(i%10+'0'));
334 }
335 }
336
337
338
339
340
341
342 public static String nonNull(String s)
343 {
344 if (s==null)
345 return "";
346 return s;
347 }
348
349
350 public static boolean equals(String s,char[] buf, int offset, int length)
351 {
352 if (s.length()!=length)
353 return false;
354 for (int i=0;i<length;i++)
355 if (buf[offset+i]!=s.charAt(i))
356 return false;
357 return true;
358 }
359
360
361 public static String toUTF8String(byte[] b,int offset,int length)
362 {
363 return new String(b,offset,length,__UTF8_CHARSET);
364 }
365
366
367 public static String toString(byte[] b,int offset,int length,String charset)
368 {
369 try
370 {
371 return new String(b,offset,length,charset);
372 }
373 catch (UnsupportedEncodingException e)
374 {
375 throw new IllegalArgumentException(e);
376 }
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400 public static boolean isBlank(String str)
401 {
402 if (str == null)
403 {
404 return true;
405 }
406 int len = str.length();
407 for (int i = 0; i < len; i++)
408 {
409 if (!Character.isWhitespace(str.codePointAt(i)))
410 {
411
412 return false;
413 }
414 }
415
416 return true;
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440 public static boolean isNotBlank(String str)
441 {
442 if (str == null)
443 {
444 return false;
445 }
446 int len = str.length();
447 for (int i = 0; i < len; i++)
448 {
449 if (!Character.isWhitespace(str.codePointAt(i)))
450 {
451
452 return true;
453 }
454 }
455
456 return false;
457 }
458
459
460 public static boolean isUTF8(String charset)
461 {
462 return __UTF8.equalsIgnoreCase(charset)||__UTF8.equalsIgnoreCase(normalizeCharset(charset));
463 }
464
465
466
467 public static String printable(String name)
468 {
469 if (name==null)
470 return null;
471 StringBuilder buf = new StringBuilder(name.length());
472 for (int i=0;i<name.length();i++)
473 {
474 char c=name.charAt(i);
475 if (!Character.isISOControl(c))
476 buf.append(c);
477 }
478 return buf.toString();
479 }
480
481
482 public static String printable(byte[] b)
483 {
484 StringBuilder buf = new StringBuilder();
485 for (int i=0;i<b.length;i++)
486 {
487 char c=(char)b[i];
488 if (Character.isWhitespace(c)|| c>' ' && c<0x7f)
489 buf.append(c);
490 else
491 {
492 buf.append("0x");
493 TypeUtil.toHex(b[i],buf);
494 }
495 }
496 return buf.toString();
497 }
498
499 public static byte[] getBytes(String s)
500 {
501 return s.getBytes(__ISO_8859_1_CHARSET);
502 }
503
504 public static byte[] getUtf8Bytes(String s)
505 {
506 return s.getBytes(__UTF8_CHARSET);
507 }
508
509 public static byte[] getBytes(String s,String charset)
510 {
511 try
512 {
513 return s.getBytes(charset);
514 }
515 catch(Exception e)
516 {
517 LOG.warn(e);
518 return s.getBytes();
519 }
520 }
521
522
523
524
525
526
527
528
529
530
531 public static String sidBytesToString(byte[] sidBytes)
532 {
533 StringBuilder sidString = new StringBuilder();
534
535
536 sidString.append("S-");
537
538
539 sidString.append(Byte.toString(sidBytes[0])).append('-');
540
541 StringBuilder tmpBuilder = new StringBuilder();
542
543
544 for (int i = 2; i <= 7; ++i)
545 {
546 tmpBuilder.append(Integer.toHexString(sidBytes[i] & 0xFF));
547 }
548
549 sidString.append(Long.parseLong(tmpBuilder.toString(), 16));
550
551
552 int subAuthorityCount = sidBytes[1];
553
554
555 for (int i = 0; i < subAuthorityCount; ++i)
556 {
557 int offset = i * 4;
558 tmpBuilder.setLength(0);
559
560 tmpBuilder.append(String.format("%02X%02X%02X%02X",
561 (sidBytes[11 + offset] & 0xFF),
562 (sidBytes[10 + offset] & 0xFF),
563 (sidBytes[9 + offset] & 0xFF),
564 (sidBytes[8 + offset] & 0xFF)));
565 sidString.append('-').append(Long.parseLong(tmpBuilder.toString(), 16));
566 }
567
568 return sidString.toString();
569 }
570
571
572
573
574
575
576
577
578 public static byte[] sidStringToBytes( String sidString )
579 {
580 String[] sidTokens = sidString.split("-");
581
582 int subAuthorityCount = sidTokens.length - 3;
583
584 int byteCount = 0;
585 byte[] sidBytes = new byte[1 + 1 + 6 + (4 * subAuthorityCount)];
586
587
588 sidBytes[byteCount++] = (byte)Integer.parseInt(sidTokens[1]);
589
590
591 sidBytes[byteCount++] = (byte)subAuthorityCount;
592
593
594 String hexStr = Long.toHexString(Long.parseLong(sidTokens[2]));
595
596 while( hexStr.length() < 12)
597 {
598 hexStr = "0" + hexStr;
599 }
600
601
602 for ( int i = 0 ; i < hexStr.length(); i = i + 2)
603 {
604 sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(i, i + 2),16);
605 }
606
607
608 for ( int i = 3; i < sidTokens.length ; ++i)
609 {
610 hexStr = Long.toHexString(Long.parseLong(sidTokens[i]));
611
612 while( hexStr.length() < 8)
613 {
614 hexStr = "0" + hexStr;
615 }
616
617
618 for ( int j = hexStr.length(); j > 0; j = j - 2)
619 {
620 sidBytes[byteCount++] = (byte)Integer.parseInt(hexStr.substring(j-2, j),16);
621 }
622 }
623
624 return sidBytes;
625 }
626
627
628
629
630
631
632
633
634
635 public static int toInt(String string)
636 {
637 int val = 0;
638 boolean started = false;
639 boolean minus = false;
640
641 for (int i = 0; i < string.length(); i++)
642 {
643 char b = string.charAt(i);
644 if (b <= ' ')
645 {
646 if (started)
647 break;
648 }
649 else if (b >= '0' && b <= '9')
650 {
651 val = val * 10 + (b - '0');
652 started = true;
653 }
654 else if (b == '-' && !started)
655 {
656 minus = true;
657 }
658 else
659 break;
660 }
661
662 if (started)
663 return minus?(-val):val;
664 throw new NumberFormatException(string);
665 }
666
667
668
669
670
671
672
673
674 public static long toLong(String string)
675 {
676 long val = 0;
677 boolean started = false;
678 boolean minus = false;
679
680 for (int i = 0; i < string.length(); i++)
681 {
682 char b = string.charAt(i);
683 if (b <= ' ')
684 {
685 if (started)
686 break;
687 }
688 else if (b >= '0' && b <= '9')
689 {
690 val = val * 10L + (b - '0');
691 started = true;
692 }
693 else if (b == '-' && !started)
694 {
695 minus = true;
696 }
697 else
698 break;
699 }
700
701 if (started)
702 return minus?(-val):val;
703 throw new NumberFormatException(string);
704 }
705
706
707
708
709
710
711
712
713 public static String truncate(String str, int maxSize)
714 {
715 if (str == null)
716 {
717 return null;
718 }
719
720 if (str.length() <= maxSize)
721 {
722 return str;
723 }
724
725 return str.substring(0,maxSize);
726 }
727
728 }