1   // ========================================================================
2   // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.util;
16  
17  import java.io.UnsupportedEncodingException;
18  
19  import org.mortbay.log.Log;
20  
21  // ====================================================================
22  /** Fast String Utilities.
23   *
24   * These string utilities provide both conveniance methods and
25   * performance improvements over most standard library versions. The
26   * main aim of the optimizations is to avoid object creation unless
27   * absolutely required.
28   *
29   * @author Greg Wilkins (gregw)
30   */
31  public class StringUtil
32  {
33      public static final String ALL_INTERFACES="0.0.0.0";
34      public static final String CRLF="\015\012";
35      public static final String __LINE_SEPARATOR=
36          System.getProperty("line.separator","\n");
37         
38      public static final String __ISO_8859_1;
39      static
40      {
41          String iso=System.getProperty("ISO_8859_1");
42          if (iso==null)
43          {
44              try{
45                  new String(new byte[]{(byte)20},"ISO-8859-1");
46                  iso="ISO-8859-1";
47              }
48              catch(java.io.UnsupportedEncodingException e)
49              {
50                  iso="ISO8859_1";
51              }        
52          }
53          __ISO_8859_1=iso;
54      }
55      
56      
57      public final static String __UTF8="UTF-8";
58      public final static String __UTF8Alt="UTF8";
59      public final static String __UTF16="UTF-16";
60      
61      
62      private static char[] lowercases = {
63            '\000','\001','\002','\003','\004','\005','\006','\007',
64            '\010','\011','\012','\013','\014','\015','\016','\017',
65            '\020','\021','\022','\023','\024','\025','\026','\027',
66            '\030','\031','\032','\033','\034','\035','\036','\037',
67            '\040','\041','\042','\043','\044','\045','\046','\047',
68            '\050','\051','\052','\053','\054','\055','\056','\057',
69            '\060','\061','\062','\063','\064','\065','\066','\067',
70            '\070','\071','\072','\073','\074','\075','\076','\077',
71            '\100','\141','\142','\143','\144','\145','\146','\147',
72            '\150','\151','\152','\153','\154','\155','\156','\157',
73            '\160','\161','\162','\163','\164','\165','\166','\167',
74            '\170','\171','\172','\133','\134','\135','\136','\137',
75            '\140','\141','\142','\143','\144','\145','\146','\147',
76            '\150','\151','\152','\153','\154','\155','\156','\157',
77            '\160','\161','\162','\163','\164','\165','\166','\167',
78            '\170','\171','\172','\173','\174','\175','\176','\177' };
79  
80      /* ------------------------------------------------------------ */
81      /**
82       * fast lower case conversion. Only works on ascii (not unicode)
83       * @param s the string to convert
84       * @return a lower case version of s
85       */
86      public static String asciiToLowerCase(String s)
87      {
88          char[] c = null;
89          int i=s.length();
90  
91          // look for first conversion
92          while (i-->0)
93          {
94              char c1=s.charAt(i);
95              if (c1<=127)
96              {
97                  char c2=lowercases[c1];
98                  if (c1!=c2)
99                  {
100                     c=s.toCharArray();
101                     c[i]=c2;
102                     break;
103                 }
104             }
105         }
106 
107         while (i-->0)
108         {
109             if(c[i]<=127)
110                 c[i] = lowercases[c[i]];
111         }
112         
113         return c==null?s:new String(c);
114     }
115 
116 
117     /* ------------------------------------------------------------ */
118     public static boolean startsWithIgnoreCase(String s,String w)
119     {
120         if (w==null)
121             return true;
122         
123         if (s==null || s.length()<w.length())
124             return false;
125         
126         for (int i=0;i<w.length();i++)
127         {
128             char c1=s.charAt(i);
129             char c2=w.charAt(i);
130             if (c1!=c2)
131             {
132                 if (c1<=127)
133                     c1=lowercases[c1];
134                 if (c2<=127)
135                     c2=lowercases[c2];
136                 if (c1!=c2)
137                     return false;
138             }
139         }
140         return true;
141     }
142     
143     /* ------------------------------------------------------------ */
144     public static boolean endsWithIgnoreCase(String s,String w)
145     {
146         if (w==null)
147             return true;
148 
149         if (s==null)
150             return false;
151             
152         int sl=s.length();
153         int wl=w.length();
154         
155         if (sl<wl)
156             return false;
157         
158         for (int i=wl;i-->0;)
159         {
160             char c1=s.charAt(--sl);
161             char c2=w.charAt(i);
162             if (c1!=c2)
163             {
164                 if (c1<=127)
165                     c1=lowercases[c1];
166                 if (c2<=127)
167                     c2=lowercases[c2];
168                 if (c1!=c2)
169                     return false;
170             }
171         }
172         return true;
173     }
174     
175     /* ------------------------------------------------------------ */
176     /**
177      * returns the next index of a character from the chars string
178      */
179     public static int indexFrom(String s,String chars)
180     {
181         for (int i=0;i<s.length();i++)
182            if (chars.indexOf(s.charAt(i))>=0)
183               return i;
184         return -1;
185     }
186     
187     /* ------------------------------------------------------------ */
188     /**
189      * replace substrings within string.
190      */
191     public static String replace(String s, String sub, String with)
192     {
193         int c=0;
194         int i=s.indexOf(sub,c);
195         if (i == -1)
196             return s;
197     
198         StringBuilder buf = new StringBuilder(s.length()+with.length());
199 
200         do
201         {
202             buf.append(s.substring(c,i));
203             buf.append(with);
204             c=i+sub.length();
205         } while ((i=s.indexOf(sub,c))!=-1);
206 
207         if (c<s.length())
208             buf.append(s.substring(c,s.length()));
209 
210         return buf.toString();
211         
212     }
213 
214 
215     /* ------------------------------------------------------------ */
216     /** Remove single or double quotes.
217      */
218     public static String unquote(String s)
219     {
220         return QuotedStringTokenizer.unquote(s);
221     }
222 
223 
224     /* ------------------------------------------------------------ */
225     /** Append substring to StringBuilder 
226      * @param buf StringBuilder to append to
227      * @param s String to append from
228      * @param offset The offset of the substring
229      * @param length The length of the substring
230      */
231     public static void append(StringBuilder buf,
232                               String s,
233                               int offset,
234                               int length)
235     {
236         synchronized(buf)
237         {
238             int end=offset+length;
239             for (int i=offset; i<end;i++)
240             {
241                 if (i>=s.length())
242                     break;
243                 buf.append(s.charAt(i));
244             }
245         }
246     }
247 
248     
249     /* ------------------------------------------------------------ */
250     /**
251      * append hex digit
252      * 
253      */
254     public static void append(StringBuilder buf,byte b,int base)
255     {
256         int bi=0xff&b;
257         int c='0'+(bi/base)%base;
258         if (c>'9')
259             c= 'a'+(c-'0'-10);
260         buf.append((char)c);
261         c='0'+bi%base;
262         if (c>'9')
263             c= 'a'+(c-'0'-10);
264         buf.append((char)c);
265     }
266 
267     /* ------------------------------------------------------------ */
268     public static void append2digits(StringBuffer buf,int i)
269     {
270         if (i<100)
271         {
272             buf.append((char)(i/10+'0'));
273             buf.append((char)(i%10+'0'));
274         }
275     }
276     
277     /* ------------------------------------------------------------ */
278     public static void append2digits(StringBuilder buf,int i)
279     {
280         if (i<100)
281         {
282             buf.append((char)(i/10+'0'));
283             buf.append((char)(i%10+'0'));
284         }
285     }
286     
287     /* ------------------------------------------------------------ */
288     /** Return a non null string.
289      * @param s String
290      * @return The string passed in or empty string if it is null. 
291      */
292     public static String nonNull(String s)
293     {
294         if (s==null)
295             return "";
296         return s;
297     }
298     
299     /* ------------------------------------------------------------ */
300     public static boolean equals(String s,char[] buf, int offset, int length)
301     {
302         if (s.length()!=length)
303             return false;
304         for (int i=0;i<length;i++)
305             if (buf[offset+i]!=s.charAt(i))
306                 return false;
307         return true;
308     }
309 
310     /* ------------------------------------------------------------ */
311     public static String toUTF8String(byte[] b,int offset,int length)
312     {
313         try
314         {
315             return new String(b,offset,length,__UTF8);
316         }
317         catch (UnsupportedEncodingException e)
318         {
319             throw new IllegalArgumentException(e);
320         }
321     }
322 
323     /* ------------------------------------------------------------ */
324     public static String toString(byte[] b,int offset,int length,String charset)
325     {
326         try
327         {
328             return new String(b,offset,length,charset);
329         }
330         catch (UnsupportedEncodingException e)
331         {
332             throw new IllegalArgumentException(e);
333         }
334     }
335 
336 
337     /* ------------------------------------------------------------ */
338     public static boolean isUTF8(String charset)
339     {
340         return charset==__UTF8||__UTF8.equalsIgnoreCase(charset)||__UTF8Alt.equalsIgnoreCase(charset);
341     }
342 
343 
344     /* ------------------------------------------------------------ */
345     public static String printable(String name)
346     {
347         if (name==null)
348             return null;
349         StringBuilder buf = new StringBuilder(name.length());
350         for (int i=0;i<name.length();i++)
351         {
352             char c=name.charAt(i);
353             if (!Character.isISOControl(c))
354                 buf.append(c);
355         }
356         return buf.toString();
357     }
358     
359     public static byte[] getBytes(String s)
360     {
361         try
362         {
363             return s.getBytes(__ISO_8859_1);
364         }
365         catch(Exception e)
366         {
367             Log.warn(e);
368             return s.getBytes();
369         }
370     }
371     
372     public static byte[] getBytes(String s,String charset)
373     {
374         try
375         {
376             return s.getBytes(charset);
377         }
378         catch(Exception e)
379         {
380             Log.warn(e);
381             return s.getBytes();
382         }
383     }
384 }