KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > smack > util > StringUtils


1 /**
2  * $RCSfile$
3  * $Revision: 2720 $
4  * $Date: 2005-08-26 13:49:25 -0300 (Fri, 26 Aug 2005) $
5  *
6  * Copyright 2003-2004 Jive Software.
7  *
8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */

20
21 package org.jivesoftware.smack.util;
22
23 import java.security.MessageDigest JavaDoc;
24 import java.security.NoSuchAlgorithmException JavaDoc;
25 import java.io.UnsupportedEncodingException JavaDoc;
26 import java.util.Random JavaDoc;
27
28 /**
29  * A collection of utility methods for String objects.
30  */

31 public class StringUtils {
32
33     private static final char[] QUOTE_ENCODE = """.toCharArray();
34     private static final char[] AMP_ENCODE = "&".toCharArray();
35     private static final char[] LT_ENCODE = "<".toCharArray();
36     private static final char[] GT_ENCODE = ">".toCharArray();
37
38     /**
39      * Returns the name portion of a XMPP address. For example, for the
40      * address "matt@jivesoftware.com/Smack", "matt" would be returned. If no
41      * username is present in the address, the empty string will be returned.
42      *
43      * @param XMPPAddress the XMPP address.
44      * @return the name portion of the XMPP address.
45      */

46     public static String JavaDoc parseName(String JavaDoc XMPPAddress) {
47         if (XMPPAddress == null) {
48             return null;
49         }
50         int atIndex = XMPPAddress.indexOf("@");
51         if (atIndex <= 0) {
52             return "";
53         }
54         else {
55             return XMPPAddress.substring(0, atIndex);
56         }
57     }
58
59     /**
60      * Returns the server portion of a XMPP address. For example, for the
61      * address "matt@jivesoftware.com/Smack", "jivesoftware.com" would be returned.
62      * If no server is present in the address, the empty string will be returned.
63      *
64      * @param XMPPAddress the XMPP address.
65      * @return the server portion of the XMPP address.
66      */

67     public static String JavaDoc parseServer(String JavaDoc XMPPAddress) {
68         if (XMPPAddress == null) {
69             return null;
70         }
71         int atIndex = XMPPAddress.indexOf("@");
72         // If the String ends with '@', return the empty string.
73
if (atIndex + 1 > XMPPAddress.length()) {
74             return "";
75         }
76         int slashIndex = XMPPAddress.indexOf("/");
77         if (slashIndex > 0) {
78             return XMPPAddress.substring(atIndex + 1, slashIndex);
79         }
80         else {
81             return XMPPAddress.substring(atIndex + 1);
82         }
83     }
84
85     /**
86      * Returns the resource portion of a XMPP address. For example, for the
87      * address "matt@jivesoftware.com/Smack", "Smack" would be returned. If no
88      * resource is present in the address, the empty string will be returned.
89      *
90      * @param XMPPAddress the XMPP address.
91      * @return the resource portion of the XMPP address.
92      */

93     public static String JavaDoc parseResource(String JavaDoc XMPPAddress) {
94         if (XMPPAddress == null) {
95             return null;
96         }
97         int slashIndex = XMPPAddress.indexOf("/");
98         if (slashIndex + 1 > XMPPAddress.length() || slashIndex < 0) {
99             return "";
100         }
101         else {
102             return XMPPAddress.substring(slashIndex + 1);
103         }
104     }
105
106     /**
107      * Returns the XMPP address with any resource information removed. For example,
108      * for the address "matt@jivesoftware.com/Smack", "matt@jivesoftware.com" would
109      * be returned.
110      *
111      * @param XMPPAddress the XMPP address.
112      * @return the bare XMPP address without resource information.
113      */

114     public static String JavaDoc parseBareAddress(String JavaDoc XMPPAddress) {
115         if (XMPPAddress == null) {
116             return null;
117         }
118         int slashIndex = XMPPAddress.indexOf("/");
119         if (slashIndex < 0) {
120             return XMPPAddress;
121         }
122         else if (slashIndex == 0) {
123             return "";
124         }
125         else {
126             return XMPPAddress.substring(0, slashIndex);
127         }
128     }
129
130     /**
131      * Escapes all necessary characters in the String so that it can be used
132      * in an XML doc.
133      *
134      * @param string the string to escape.
135      * @return the string with appropriate characters escaped.
136      */

137     public static String JavaDoc escapeForXML(String JavaDoc string) {
138         if (string == null) {
139             return null;
140         }
141         char ch;
142         int i=0;
143         int last=0;
144         char[] input = string.toCharArray();
145         int len = input.length;
146         StringBuffer JavaDoc out = new StringBuffer JavaDoc((int)(len*1.3));
147         for (; i < len; i++) {
148             ch = input[i];
149             if (ch > '>') {
150                 continue;
151             }
152             else if (ch == '<') {
153                 if (i > last) {
154                     out.append(input, last, i - last);
155                 }
156                 last = i + 1;
157                 out.append(LT_ENCODE);
158             }
159             else if (ch == '>') {
160                 if (i > last) {
161                     out.append(input, last, i - last);
162                 }
163                 last = i + 1;
164                 out.append(GT_ENCODE);
165             }
166
167             else if (ch == '&') {
168                 if (i > last) {
169                     out.append(input, last, i - last);
170                 }
171                 // Do nothing if the string is of the form &#235; (unicode value)
172
if (!(len > i + 5
173                     && input[i + 1] == '#'
174                     && Character.isDigit(input[i + 2])
175                     && Character.isDigit(input[i + 3])
176                     && Character.isDigit(input[i + 4])
177                     && input[i + 5] == ';')) {
178                         last = i + 1;
179                         out.append(AMP_ENCODE);
180                     }
181             }
182             else if (ch == '"') {
183                 if (i > last) {
184                     out.append(input, last, i - last);
185                 }
186                 last = i + 1;
187                 out.append(QUOTE_ENCODE);
188             }
189         }
190         if (last == 0) {
191             return string;
192         }
193         if (i > last) {
194             out.append(input, last, i - last);
195         }
196         return out.toString();
197     }
198
199     /**
200      * Used by the hash method.
201      */

202     private static MessageDigest JavaDoc digest = null;
203
204     /**
205      * Hashes a String using the SHA-1 algorithm and returns the result as a
206      * String of hexadecimal numbers. This method is synchronized to avoid
207      * excessive MessageDigest object creation. If calling this method becomes
208      * a bottleneck in your code, you may wish to maintain a pool of
209      * MessageDigest objects instead of using this method.
210      * <p>
211      * A hash is a one-way function -- that is, given an
212      * input, an output is easily computed. However, given the output, the
213      * input is almost impossible to compute. This is useful for passwords
214      * since we can store the hash and a hacker will then have a very hard time
215      * determining the original password.
216      *
217      * @param data the String to compute the hash of.
218      * @return a hashed version of the passed-in String
219      */

220     public synchronized static String JavaDoc hash(String JavaDoc data) {
221         if (digest == null) {
222             try {
223                 digest = MessageDigest.getInstance("SHA-1");
224             }
225             catch (NoSuchAlgorithmException JavaDoc nsae) {
226                 System.err.println("Failed to load the SHA-1 MessageDigest. " +
227                 "Jive will be unable to function normally.");
228             }
229         }
230         // Now, compute hash.
231
try {
232             digest.update(data.getBytes("UTF-8"));
233         }
234         catch (UnsupportedEncodingException JavaDoc e) {
235             System.err.println(e);
236         }
237         return encodeHex(digest.digest());
238     }
239
240     /**
241      * Encodes an array of bytes as String representation of hexadecimal.
242      *
243      * @param bytes an array of bytes to convert to a hex string.
244      * @return generated hex string.
245      */

246     public static String JavaDoc encodeHex(byte[] bytes) {
247         StringBuffer JavaDoc hex = new StringBuffer JavaDoc(bytes.length * 2);
248
249         for (int i=0; i<bytes.length; i++) {
250             if (((int) bytes[i] & 0xff) < 0x10) {
251                 hex.append("0");
252             }
253             hex.append(Integer.toString((int) bytes[i] & 0xff, 16));
254         }
255         
256         return hex.toString();
257     }
258
259     //*********************************************************************
260
//* Base64 - a simple base64 encoder and decoder.
261
//*
262
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
263
//*
264
//* This code may be freely used for any purpose, either personal
265
//* or commercial, provided the authors copyright notice remains
266
//* intact.
267
//*********************************************************************
268

269     private static final int fillchar = '=';
270     private static final String JavaDoc cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
271                                     + "0123456789+/";
272
273     /**
274      * Encodes a String as a base64 String.
275      *
276      * @param data a String to encode.
277      * @return a base64 encoded String.
278      */

279     public static String JavaDoc encodeBase64(String JavaDoc data) {
280         byte [] bytes = null;
281         try {
282             bytes = data.getBytes("ISO-8859-1");
283         }
284         catch (UnsupportedEncodingException JavaDoc uee) {
285             uee.printStackTrace();
286         }
287         return encodeBase64(bytes);
288     }
289
290     /**
291      * Encodes a byte array into a base64 String.
292      *
293      * @param data a byte array to encode.
294      * @return a base64 encode String.
295      */

296     public static String JavaDoc encodeBase64(byte[] data) {
297         int c;
298         int len = data.length;
299         StringBuffer JavaDoc ret = new StringBuffer JavaDoc(((len / 3) + 1) * 4);
300         for (int i = 0; i < len; ++i) {
301             c = (data[i] >> 2) & 0x3f;
302             ret.append(cvt.charAt(c));
303             c = (data[i] << 4) & 0x3f;
304             if (++i < len)
305                 c |= (data[i] >> 4) & 0x0f;
306
307             ret.append(cvt.charAt(c));
308             if (i < len) {
309                 c = (data[i] << 2) & 0x3f;
310                 if (++i < len)
311                     c |= (data[i] >> 6) & 0x03;
312
313                 ret.append(cvt.charAt(c));
314             }
315             else {
316                 ++i;
317                 ret.append((char) fillchar);
318             }
319
320             if (i < len) {
321                 c = data[i] & 0x3f;
322                 ret.append(cvt.charAt(c));
323             }
324             else {
325                 ret.append((char) fillchar);
326             }
327         }
328         return ret.toString();
329     }
330
331     /**
332      * Decodes a base64 String.
333      *
334      * @param data a base64 encoded String to decode.
335      * @return the decoded String.
336      */

337     public static byte[] decodeBase64(String JavaDoc data) {
338         byte [] bytes = null;
339         try {
340             bytes = data.getBytes("ISO-8859-1");
341             return decodeBase64(bytes).getBytes("ISO-8859-1");
342         }
343         catch (UnsupportedEncodingException JavaDoc uee) {
344             uee.printStackTrace();
345         }
346         return new byte[] { };
347     }
348
349     /**
350      * Decodes a base64 aray of bytes.
351      *
352      * @param data a base64 encode byte array to decode.
353      * @return the decoded String.
354      */

355     private static String JavaDoc decodeBase64(byte[] data) {
356         int c, c1;
357         int len = data.length;
358         StringBuffer JavaDoc ret = new StringBuffer JavaDoc((len * 3) / 4);
359         for (int i = 0; i < len; ++i) {
360             c = cvt.indexOf(data[i]);
361             ++i;
362             c1 = cvt.indexOf(data[i]);
363             c = ((c << 2) | ((c1 >> 4) & 0x3));
364             ret.append((char) c);
365             if (++i < len) {
366                 c = data[i];
367                 if (fillchar == c)
368                     break;
369
370                 c = cvt.indexOf(c);
371                 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
372                 ret.append((char) c1);
373             }
374
375             if (++i < len) {
376                 c1 = data[i];
377                 if (fillchar == c1)
378                     break;
379
380                 c1 = cvt.indexOf(c1);
381                 c = ((c << 6) & 0xc0) | c1;
382                 ret.append((char) c);
383             }
384         }
385         return ret.toString();
386     }
387
388     /**
389      * Pseudo-random number generator object for use with randomString().
390      * The Random class is not considered to be cryptographically secure, so
391      * only use these random Strings for low to medium security applications.
392      */

393     private static Random JavaDoc randGen = new Random JavaDoc();
394
395     /**
396      * Array of numbers and letters of mixed case. Numbers appear in the list
397      * twice so that there is a more equal chance that a number will be picked.
398      * We can use the array to get a random number or letter by picking a random
399      * array index.
400      */

401     private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz" +
402                     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
403
404     /**
405      * Returns a random String of numbers and letters (lower and upper case)
406      * of the specified length. The method uses the Random class that is
407      * built-in to Java which is suitable for low to medium grade security uses.
408      * This means that the output is only pseudo random, i.e., each number is
409      * mathematically generated so is not truly random.<p>
410      *
411      * The specified length must be at least one. If not, the method will return
412      * null.
413      *
414      * @param length the desired length of the random String to return.
415      * @return a random String of numbers and letters of the specified length.
416      */

417     public static final String JavaDoc randomString(int length) {
418         if (length < 1) {
419             return null;
420         }
421         // Create a char buffer to put random letters and numbers in.
422
char [] randBuffer = new char[length];
423         for (int i=0; i<randBuffer.length; i++) {
424             randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
425         }
426         return new String JavaDoc(randBuffer);
427     }
428
429     private StringUtils() {
430         // Not instantiable.
431
}
432 }
Popular Tags